home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / pmode / pmode307 / pmode.asm < prev    next >
Encoding:
Assembly Source File  |  1994-12-04  |  139.1 KB  |  3,253 lines

  1. ; PMODE v3.07 DPMI/VCPI/XMS/raw protected mode interface kernel.
  2. ; Copyright (c) 1994, Tran (a.k.a. Thomas Pytel).
  3.  
  4. public  _pm_selectors, _pm_pagetables, _pm_rmstacklen, _pm_rmstacks
  5. public  _pm_callbacks, _pm_pmstacklen, _pm_pmstacks, _pm_mode
  6. public  pmstackbase, pmstacktop, rmstackbase, rmstacktop
  7.  
  8. public  _pm_info, _pm_init
  9.  
  10. .386p
  11. locals
  12. PMODE_TEXT      segment para public use16 'CODE'
  13. assume  cs:PMODE_TEXT, ds:PMODE_TEXT
  14.  
  15. off             equ     offset
  16.  
  17. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  18. ; DATA
  19. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  20. SELCODE         = 08h                   ; PMODE_TEXT code selector
  21. SELZERO         = 10h                   ; selector of entire memory space
  22. SELCALLBACKDS   = 18h                   ; callback DS selector
  23. SELREAL         = 20h                   ; real mode attributes selector
  24. SELVCPITSS      = 28h                   ; TSS selector for VCPI
  25. SELVCPICODE     = 30h                   ; VCPI call code selector
  26. SYSSELECTORS    = 9                     ; number of system selectors in GDT
  27.  
  28. align 4
  29. dpmiepmode      dd      ?               ; DPMI enter pmode addx
  30. codebase        dd      ?               ; PMODE_TEXT linear address
  31. vcpistrucaddx   dd      off vcpi_cr3    ; VCPI switch structure linear address
  32. vcpiswitchstack dd      ?               ; VCPI temporary mode switch stack
  33. oldint15vector  dd      ?               ; preserved INT 15h vector
  34. int3vector      dd      intrmatrix+3    ; protected mode INT 3 vector
  35.                 dw      SELCODE
  36.                 dw      ?               ; just here for alignment
  37.  
  38. pmstacklen      dd      ?               ; protected mode stack length in bytes
  39. pmstackbase    dd    ?        ; bottom of protected mode stack area
  40. pmstacktop      dd      ?               ; top of protected mode stack area
  41. callbackbase    dd      ?               ; base of real mode callbacks
  42. callbackseg     dw      ?               ; segment of callbacks
  43.  
  44. selzero         dw      SELZERO         ; for immediate segreg loading
  45. selcallbackds   dw      SELCALLBACKDS   ; for immediate segreg loading
  46.  
  47. rawextmemused   dw      1               ; raw extended memory used in K
  48. rawextmembase   dd      0ffffffffh      ; raw extended memory base
  49. rawextmemtop    dd      0               ; raw extended memory top
  50.  
  51. rmstackbase     dw      ?               ; bottom of real mode stack area
  52. rmstacktop      dw      ?               ; top of real mode stack area
  53. rmstackparmtop  dw      ?               ; for functions 0300h, 0301h, 0302h
  54.  
  55. gdtseg          dw      ?               ; segment of GDT
  56.  
  57. gdtlimit        dw      ?               ; GDT limit                          |
  58. gdtbase         dd      ?               ; GDT base                           |
  59. idtlimit        dw      7ffh            ; IDT limit                         |
  60. idtbase         dd      ?               ; IDT base                          |
  61. rmidtlimit      dw      3ffh            ; real mode IDT limit                |
  62. rmidtbase       dd      0               ; real mode IDT base                 |
  63.  
  64. rmtopmswrout    dw      off v_rmtopmsw  ; addx of real to protected routine
  65. pmtormswrout    dd      off v_pmtormsw  ; addx of protected to real routine
  66.  
  67. pagetablebase   dd      ?               ; base of page table area
  68. pagetabletop    dd      ?               ; top of page table area
  69. pagetablefree   dd      ?               ; base of available page table area
  70.                 db      ?               ; just here for alignment
  71.  
  72. _pm_pagetables  db      1               ; number of page tables under VCPI
  73. _pm_selectors   dw      64              ; max selectors under VCPI/XMS/raw
  74. _pm_rmstacklen  dw      40h             ; real mode stack length, in para
  75. _pm_pmstacklen  dw      80h             ; protected mode stack length, in para
  76. _pm_rmstacks    db      4               ; real mode stack nesting
  77. _pm_pmstacks    db      2               ; protected mode stack nesting
  78. _pm_callbacks   db      16              ; number of real mode callbacks
  79. _pm_mode        db      1               ; mode bits
  80.  
  81. processortype   db      ?               ; processor type                     |
  82. pmodetype       db      2               ; protected mode type                |
  83. picslave        db      70h             ; PIC slave base interrupt          |
  84. picmaster       db      8               ; PIC master base interrupt         |
  85.  
  86. tempd0          label   dword           ; temporary variables                |
  87. tempw0          label   word            ;                                    |
  88. tempb0          db      ?               ;                                    |
  89. tempb1          db      ?               ;                                    |
  90. tempw1          label   word            ;                                    |
  91. tempb2          db      ?               ;                                    |
  92. tempb3          db      ?               ;                                    |
  93. tempd1          label   dword           ;                                    |
  94. tempw2          label   word            ;                                    |
  95. tempb4          db      ?               ;                                    |
  96. tempb5          db      ?               ;                                    |
  97. tempw3          label   word            ;                                    |
  98. tempb6          db      ?               ;                                    |
  99. tempb7          db      ?               ;                                    |
  100.  
  101. xms_callip      dw      ?               ; XMS driver offset                 |
  102. xms_callcs      dw      ?               ; XMS driver segment                |
  103.  
  104. vcpi_cr3        dd      ?               ; VCPI CR3 value for protected mode  |
  105. vcpi_gdtaddx    dd      off gdtlimit    ; linear addx of GDT limit and base  |
  106. vcpi_idtaddx    dd      off idtlimit    ; linear addx of IDT limit and base  |
  107. vcpi_selldt     dw      0               ; LDT selector for protected mode    |
  108. vcpi_seltss     dw      SELVCPITSS      ; TSS selector for protected mode    |
  109. vcpi_eip        dd      off v_rmtopmswpm; destination EIP in protected mode  |
  110. vcpi_cs         dw      SELCODE         ; destination CS in protected mode   |
  111.  
  112. vcpi_calleip    dd      ?               ; VCPI protected mode call offset   |
  113. vcpi_callcs     dw      SELVCPICODE     ; VCPI protected mode call selector |
  114.  
  115. initrouttbl     dw      r_init, x_init, v_init, d_init
  116.  
  117. int31functbl    dw      0900h, 0901h, 0902h, 0000h, 0001h, 0003h, 0006h, 0007h
  118.                 dw      0008h, 0009h, 0200h, 0201h, 0204h, 0205h, 0305h, 0306h
  119.                 dw      0400h
  120.                 dw      000ah, 000bh, 000ch, 000eh, 000fh
  121.                 dw      0300h, 0301h, 0302h
  122.                 dw      0303h, 0304h
  123.                 dw      0500h, 0501h, 0502h, 0503h, 050ah
  124. INT31FUNCNUM    = ($ - int31functbl) / 2
  125.  
  126. int31routtbl    dw      int310900, int310901, int310902, int310000
  127.                 dw      int310001, int310003, int310006, int310007
  128.                 dw      int310008, int310009, int310200, int310201
  129.                 dw      int310204, int310205, int310305, int310306
  130.                 dw      int310400
  131.                 dw      int31000a, int31000b, int31000c, int31000e, int31000f
  132.                 dw      int310300, int310301, int310302
  133.                 dw      int310303, int310304
  134. int31mrouttbl   dw      int310500v, int310501v, int310502v, int310503v
  135.                 dw      int31050av
  136. int31mxrouttbl  dw      int310500x, int310501x, int310502x, int310503x
  137.                 dw      int31050ax
  138. int31mrrouttbl  dw      int310500r, int310501r, int310502r, int310503r
  139.                 dw      int31050ar
  140. int31mnrouttbl  dw      int310500rnomem, int31fail8013, int31fail8023
  141.                 dw      int31fail8023, int31fail8023
  142.  
  143. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  144. ; DETECT/INIT CODE
  145. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  146.  
  147. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  148. ; Get protected mode info
  149. ; Out:
  150. ;   AX = return code:
  151. ;     0000h = successful
  152. ;     0001h = no 80386+ detected
  153. ;     0002h = system already in protected mode and no VCPI or DPMI found
  154. ;     0003h = DPMI - host is not 32bit
  155. ;   CF = set on error, if no error:
  156. ;     BX = number of paragraphs needed for protected mode data (may be 0)
  157. ;     CL = processor type:
  158. ;       02h = 80286
  159. ;       03h = 80386
  160. ;       04h = 80486
  161. ;       05h = 80586
  162. ;       06h-FFh = reserved for future use
  163. ;     CH = protected mode type:
  164. ;       00h = raw
  165. ;       01h = XMS
  166. ;       02h = VCPI
  167. ;       03h = DPMI
  168. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  169. _pm_info:
  170.         push dx si di bp ds es bx cx    ; preserve registers
  171.  
  172.         push cs                         ; DS = CS (PMODE_TEXT)
  173.         pop ds
  174.  
  175.         test _pm_mode,1                 ; check order of DPMI/VCPI detection
  176.         jz short @@infof0
  177.  
  178.         call @@detect_VCPI              ; check for VCPI first
  179.         call @@detect_DPMI              ; check for DPMI second
  180.         jmp short @@infof2              ; neither found, go on to XMS check
  181.  
  182. @@infof0:
  183.         call @@detect_DPMI              ; check for DPMI first
  184.         call @@detect_VCPI              ; check for VCPI second
  185.  
  186. ;-----------------------------------------------------------------------------
  187. @@infof2:
  188.         smsw ax                         ; AX = machine status word
  189.         test al,1                       ; is system in protected mode?
  190.         mov ax,2                        ; error code in case protected mode
  191.         jnz short @@infofail            ; if in protected mode, fail
  192.  
  193.         mov ax,4300h                    ; chek for XMS
  194.         int 2fh
  195.         cmp al,80h                      ; XMS present?
  196.         sete ch                         ; if yes, pmode type is XMS
  197.  
  198.         mov bx,80h                      ; BX = memory requirement (IDT)
  199.  
  200. ;-----------------------------------------------------------------------------
  201. @@infof1:
  202.         movzx ax,_pm_rmstacks           ; size of real mode stack area
  203.         imul ax,_pm_rmstacklen
  204.         add bx,ax
  205.  
  206.         movzx ax,_pm_pmstacks           ; size of protected mode stack area
  207.         imul ax,_pm_pmstacklen
  208.         add bx,ax
  209.  
  210.         movzx ax,_pm_callbacks          ; size of callbacks
  211.         imul ax,25
  212.         add ax,0fh
  213.         shr ax,4
  214.         add bx,ax
  215.  
  216.         mov ax,_pm_selectors            ; size of GDT
  217.         add ax,1+SYSSELECTORS+5
  218.         shr ax,1
  219.         add bx,ax
  220.  
  221.         jmp short @@infook              ; go to done ok
  222.  
  223. ;-----------------------------------------------------------------------------
  224. @@infofail:
  225.         pop cx bx                       ; restore BX and CX
  226.         stc                             ; carry set, failed
  227.         jmp short @@infodone
  228.  
  229. ;-----------------------------------------------------------------------------
  230. @@infook:
  231.         mov pmodetype,ch                ; store pmode type
  232.  
  233.         add sp,4                        ; skip BX and CX on stack
  234.         xor ax,ax                       ; success code, also clear carry flag
  235.  
  236. ;-----------------------------------------------------------------------------
  237. @@infodone:
  238.         pop es ds bp di si dx           ; restore other registers
  239.         retf                            ; return
  240.  
  241. ;─────────────────────────────────────────────────────────────────────────────
  242. @@detect_DPMI:                          ; detect a DPMI host
  243.         pop bp                          ; pop return address from stack
  244.  
  245.         mov ax,1687h                    ; check for DPMI
  246.         int 2fh
  247.  
  248.         or ax,ax                        ; DPMI present?
  249.         jnz short @@detect_DPMIdone     ; if no, exit routine
  250.  
  251.         mov ax,3                        ; error code in case DPMI not 32bit
  252.         test bl,1                       ; is DPMI 32bit?
  253.         jz @@infofail                   ; if no, fail
  254.  
  255.         mov ax,1                        ; error code in case no processor 386+
  256.         cmp cl,3                        ; is processor 386+? (redundant)
  257.         jb @@infofail                   ; if no, fail
  258.  
  259.         mov word ptr dpmiepmode[0],di   ; store DPMI initial mode switch addx
  260.         mov word ptr dpmiepmode[2],es
  261.  
  262.         mov bx,si                       ; BX = number of paragraphs needed
  263.         mov ch,3                        ; pmode type is 3 (DPMI)
  264.  
  265.         jmp @@infook                    ; go to done ok
  266.  
  267. @@detect_DPMIdone:
  268.         jmp bp                          ; return to calling routine
  269.  
  270. ;─────────────────────────────────────────────────────────────────────────────
  271. @@detect_VCPI:                          ; detect a VCPI server
  272.         pop bp                          ; pop return address from stack
  273.  
  274.         call @@detect_processor         ; get processor type
  275.  
  276.         mov ax,1                        ; error code in case no processor 386+
  277.         cmp cl,3                        ; is processor 386+?
  278.         jb @@infofail                   ; if no, no VCPI
  279.  
  280.         mov processortype,cl            ; store processor type
  281.  
  282.         xor ax,ax                       ; get INT 67h vector
  283.         mov es,ax
  284.         mov ax,es:[67h*4]
  285.         or ax,es:[67h*4+2]              ; is vector NULL
  286.         jz short @@detect_VCPIdone      ; if yes, no VCPI
  287.  
  288.         mov ax,0de00h                   ; call VCPI installation check
  289.         int 67h
  290.         or ah,ah                        ; AH returned as 0?
  291.         jnz short @@detect_VCPIdone     ; if no, no VCPI
  292.  
  293.         movzx bx,_pm_pagetables         ; BX = VCPI page table memory needed
  294.         shl bx,8                        ; 100h paragraphs per page table
  295.         add bx,100h+0ffh+7+80h          ; + page dir + align buf + TSS + IDT
  296.  
  297.         mov ch,2                        ; pmode type is 2 (VCPI)
  298.  
  299.         jmp @@infof1                    ; go to figure other memory needed
  300.  
  301. @@detect_VCPIdone:
  302.         jmp bp                          ; return to calling routine
  303.  
  304. ;─────────────────────────────────────────────────────────────────────────────
  305. @@detect_processor:                     ; get processor: 286, 386, 486, or 586
  306.         xor cl,cl                       ; processor type 0 in case of exit
  307.  
  308.         pushf                           ; transfer FLAGS to BX
  309.         pop bx
  310.  
  311.         mov ax,bx                       ; try to clear high 4 bits of FLAGS
  312.         and ah,0fh
  313.  
  314.         push ax                         ; transfer AX to FLAGS
  315.         popf
  316.         pushf                           ; transfer FLAGS back to AX
  317.         pop ax
  318.  
  319.         and ah,0f0h                     ; isolate high 4 bits
  320.         cmp ah,0f0h
  321.         je short @@detect_processordone ; if bits are set, CPU is 8086/8
  322.  
  323.         mov cl,2                        ; processor type 2 in case of exit
  324.  
  325.         or bh,0f0h                      ; try to set high 4 bits of FLAGS
  326.  
  327.         push bx                         ; transfer BX to FLAGS
  328.         popf
  329.         pushf                           ; transfer FLAGS to AX
  330.         pop ax
  331.  
  332.         and ah,0f0h                     ; isolate high 4 bits
  333.         jz short @@detect_processordone ; if bits are not set, CPU is 80286
  334.  
  335.         inc cx                          ; processor type 3 in case of exit
  336.  
  337.         push eax ebx                    ; preserve 32bit registers
  338.  
  339.         pushfd                          ; transfer EFLAGS to EBX
  340.         pop ebx
  341.  
  342.         mov eax,ebx                     ; try to flip AC bit in EFLAGS
  343.         xor eax,40000h
  344.  
  345.         push eax                        ; transfer EAX to EFLAGS
  346.         popfd
  347.         pushfd                          ; transfer EFLAGS back to EAX
  348.         pop eax
  349.  
  350.         xor eax,ebx                     ; AC bit fliped?
  351.         jz short @@detect_processordone2; if no, CPU is 386
  352.  
  353.         inc cx                          ; processor type 4 in case of exit
  354.  
  355.         mov eax,ebx                     ; try to flip ID bit in EFLAGS
  356.         xor eax,200000h
  357.  
  358.         push eax                        ; transfer EAX to EFLAGS
  359.         popfd
  360.         pushfd                          ; transfer EFLAGS back to EAX
  361.         pop eax
  362.  
  363.         xor eax,ebx                     ; ID bit fliped?
  364.         jz short @@detect_processordone2; if no, CPU is 486
  365.  
  366.         inc cx                          ; processor type 5, CPU is 586
  367.  
  368. @@detect_processordone2:
  369.         pop ebx eax                     ; restore 32bit registers
  370.  
  371. @@detect_processordone:
  372.         ret                             ; return
  373.  
  374. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  375. ; Initialize protected mode
  376. ; In:
  377. ;   ES = real mode segment for protected mode data (ignored if not needed)
  378. ; Out:
  379. ;   AX = return code:
  380. ;     0000h = successful
  381. ;     0001h = no 80386+ detected
  382. ;     0002h = system already in protected mode and no VCPI or DPMI found
  383. ;     0003h = DPMI - host is not 32bit
  384. ;     0004h = could not enable A20 gate
  385. ;     0005h = DPMI - could not enter 32bit protected mode
  386. ;     0006h = DPMI - could not allocate needed selectors
  387. ;   CF = set on error, if no error:
  388. ;     ESP = high word clear
  389. ;     CS = 16bit selector for real mode CS with limit of 64k
  390. ;     SS = selector for real mode SS with limit of 64k
  391. ;     DS = selector for real mode DS with limit of 64k
  392. ;     ES = selector for PSP with limit of 100h
  393. ;     FS = 0 (NULL selector)
  394. ;     GS = 0 (NULL selector)
  395. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  396. _pm_init:
  397.         push bx cx                      ; get initial info on protected mode
  398.         call far ptr _pm_info
  399.         pop cx bx
  400.         jnc short @@initf0              ; error?
  401.  
  402.         retf                            ; yup, abort
  403.  
  404. @@initf0:                               ; no error, init protected mode
  405.         pushad
  406.         push ds
  407.         mov bp,sp
  408.         push cs                         ; DS = PMODE_TEXT
  409.         pop ds
  410.         cld
  411.  
  412.         mov eax,PMODE_TEXT              ; set base addx of PMODE_TEXT
  413.         shl eax,4
  414.         mov codebase,eax
  415.  
  416.         movzx bx,pmodetype              ; jump to appropriate init code
  417.         shl bx,1
  418.         jmp initrouttbl[bx]
  419.  
  420. ;═════════════════════════════════════════════════════════════════════════════
  421. d_init:                                 ; DPMI protected mode init
  422.         pop ds                          ; get original caller DS from stack
  423.         mov ax,1                        ; enter DPMI protected mode
  424.         call cs:dpmiepmode
  425.         push ds                         ; put DS back onto stack
  426.         jnc short dvxr_init             ; error? if not, go on with init
  427.  
  428.         mov bx,6                        ; error entering protected mode, set
  429.         cmp ax,8011h                    ;  error code and abort
  430.         stc
  431.         je short init_done
  432.         mov bl,5                        ; error code 5, not 6
  433.  
  434. ;-----------------------------------------------------------------------------
  435. init_done:                              ; return with return code
  436.         mov [bp+30],bx
  437.         pop ds
  438.         popad
  439.         retf
  440.  
  441. ;─────────────────────────────────────────────────────────────────────────────
  442. dvxr_init:                              ; DPMI/VCPI/XMS/raw common init tail
  443.         xor ax,ax                       ; allocate selector for return code
  444.         mov cx,1
  445.         int 31h
  446.         jnc short @@dvxr_initf0
  447.  
  448.         mov ah,4ch                      ; could not allocate selector
  449.         int 21h                         ; terminate immediately
  450.  
  451. @@dvxr_initf0:
  452.         mov bx,ax                       ; new code descriptor for return
  453.  
  454.         mov ax,0007h                    ; set base address of calling segment
  455.         xor cx,cx
  456.         mov dx,[bp+36]
  457.         shld cx,dx,4
  458.         shl dx,4
  459.         int 31h
  460.  
  461.         mov ax,0008h                    ; set selector limit of 64k
  462.         xor cx,cx
  463.         mov dx,0ffffh
  464.         int 31h
  465.  
  466.         mov ax,0009h                    ; set selector type and access rights
  467.         mov dx,cs                       ; get DPL from current CPL, and access
  468.         lar cx,dx                       ;  rights and type from current CS
  469.         shr cx,8                        ; type is already 16bit code segment
  470.         int 31h
  471.  
  472. @@dvxr_initdone:
  473.         mov [bp+36],bx                  ; store selector in return address
  474.         xor bx,bx                       ; init successful, carry clear
  475.         jmp init_done
  476.  
  477. ;═════════════════════════════════════════════════════════════════════════════
  478. v_init:                                 ; VCPI protected mode init
  479.         mov ax,0de0ah                   ; get PIC mappings
  480.         int 67h
  481.         mov picmaster,bl
  482.         mov picslave,cl
  483.  
  484.         mov eax,codebase                ; adjust addresses for VCPI structure
  485.         add vcpi_gdtaddx,eax
  486.         add vcpi_idtaddx,eax
  487.         add vcpistrucaddx,eax
  488.  
  489.         mov dx,es                       ; align data area on page
  490.         add dx,0ffh
  491.         xor dl,dl
  492.         mov es,dx
  493.  
  494.         movzx eax,dx                    ; set base and top of page table area
  495.         shl eax,4
  496.         add eax,1000h
  497.         mov pagetablebase,eax
  498.         movzx ecx,_pm_pagetables
  499.         shl ecx,12
  500.         add eax,ecx
  501.         mov pagetabletop,eax
  502.  
  503.         xor di,di                       ; clear page dir and first page table
  504.         mov cx,1000h
  505.         xor ax,ax
  506.         rep stos word ptr es:[di]
  507.  
  508.         mov gs,dx                       ; GS = segment of page directory
  509.         lea eax,[edx+100h]
  510.         mov es,ax                       ; ES = segment of first page table
  511.         mov fs,ax                       ; FS = segment of first page table
  512.  
  513.         push ss                         ; stack space for VCPI descriptors
  514.         pop ds
  515.         sub sp,8*3
  516.         mov si,sp
  517.  
  518.         xor di,di                       ; get VCPI protected mode interface
  519.         mov ax,0de01h
  520.         int 67h
  521.  
  522.         push cs                         ; DS = PMODE_TEXT
  523.         pop ds
  524.  
  525.         movzx eax,di                    ; set base of usable page table area
  526.         add eax,pagetablebase
  527.         add pagetablefree,eax
  528.  
  529.         mov vcpi_calleip,ebx            ; store protected mode VCPI call EIP
  530.         movzx si,dh                     ; get physical address of page dir
  531.         shl si,2                        ;  from first page table for CR3
  532.         lods dword ptr fs:[si]
  533.         mov vcpi_cr3,eax
  534.  
  535. @@v_initl0:
  536.         and byte ptr es:[di+1],0f1h     ; clear bits 9-11 in copied page table
  537.         sub di,4
  538.         jnc @@v_initl0
  539.  
  540.         mov dx,es                       ; DX = current page table segment
  541.         xor ebx,ebx                     ; index in page dir, also loop counter
  542.         jmp short @@v_initl1f0
  543.  
  544. @@v_initl1:
  545.         xor di,di                       ; clear page table
  546.         mov cx,800h
  547.         xor ax,ax
  548.         rep stos word ptr es:[di]
  549.  
  550. @@v_initl1f0:
  551.         add dx,100h                     ; increment page table segment
  552.         mov es,dx
  553.  
  554.         lods dword ptr fs:[si]          ; set physical address of page table
  555.         mov gs:[ebx*4],eax              ;  in page directory
  556.  
  557.         inc bx                          ; increment index in page directory
  558.         cmp bl,_pm_pagetables           ; at end of page tables?
  559.         jb @@v_initl1                   ; if no, loop
  560.  
  561. ;-----------------------------------------------------------------------------
  562.         push dx                         ; preserve seg of TSS for later use
  563.  
  564.         xor di,di                       ; clear TSS with all 0, not really
  565.         mov cx,34h                      ;  needed, but just to be safe
  566.         xor ax,ax
  567.         rep stos word ptr es:[di]
  568.  
  569.         mov eax,vcpi_cr3                ; set CR3 in TSS
  570.         mov es:[1ch],eax
  571.         mov dword ptr es:[64h],680000h  ; set offset of I/O permission bitmap
  572.                                         ;  and clear T bit
  573.         add dx,7                        ; increment next data area ptr
  574.         mov es,dx
  575.  
  576. ;─────────────────────────────────────────────────────────────────────────────
  577. vxr_init:                               ; VCPI/XMS/raw common init tail
  578.         mov ax,es                       ; set IDT base address
  579.         movzx ebx,ax
  580.         shl ebx,4
  581.         mov idtbase,ebx
  582.  
  583.         movzx bx,_pm_rmstacks           ; set top and base of real mode stack
  584.         imul bx,_pm_rmstacklen          ;  area for interrupt redirection
  585.         add ax,80h                      ;  from protected mode
  586.         mov rmstackbase,ax
  587.         add ax,bx
  588.         mov rmstacktop,ax
  589.  
  590.         xor di,di                       ; set up IDT
  591.         mov dx,word ptr picslave
  592.         xor ecx,ecx
  593.  
  594. @@vxr_initl0:
  595.         lea eax,[SELCODE*10000h+ecx+off intrmatrix]
  596.         stos dword ptr es:[di]
  597.  
  598.         mov eax,8e00h                   ; interrupt gate type
  599.         mov bl,cl                       ; isolate high 5 bits of int num
  600.         and bl,0f8h
  601.  
  602.         test cl,0f8h                    ; one of the low 8 interrupts?
  603.         jz short @@vxr_initl0f0         ; if yes, store as interrupt gate
  604.  
  605.         cmp bl,dl                       ; one of the high IRQs?
  606.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  607.         cmp bl,dh                       ; one of the low IRQs?
  608.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  609.  
  610.         or ah,1                         ; set to trap gate type
  611.  
  612. @@vxr_initl0f0:
  613.         stos dword ptr es:[di]
  614.  
  615.         inc cl                          ; increment interrupt number
  616.         jnz @@vxr_initl0                ; loop if more interrupts to go
  617.  
  618.         mov word ptr es:[8*31h],off int31    ; protected mode INT 31h
  619.         mov word ptr es:[8*21h],off int21    ; protected mode INT 21h
  620.         mov word ptr es:[8*3],off intr  ; protected mode INT 3
  621.  
  622.         mov es,rmstacktop               ; set next data area ptr to end of
  623.                                         ;  real mode stack area
  624. ;-----------------------------------------------------------------------------
  625.     mov ax,es            ; set protected mode stack area base
  626.         movzx eax,ax                    ;  for callbacks
  627.         shl eax,4
  628.     mov pmstackbase,eax
  629.  
  630.         movzx ecx,_pm_pmstacklen        ; set protected mode stack area top
  631.         movzx ebx,_pm_pmstacks          ;  for callbacks
  632.         shl ecx,4
  633.         mov pmstacklen,ecx              ; protected mode stack size in bytes
  634.         imul ebx,ecx
  635.         add ebx,eax
  636.         mov pmstacktop,ebx              ; protected mode stack area top
  637.  
  638.         mov cl,_pm_callbacks            ; CL = number of callbacks
  639.         or cl,cl                        ; any callbacks?
  640.         jz short @@vxr_initf3           ; if no, done with this part
  641.  
  642.         mov callbackbase,ebx            ; top of stacks is base of callbacks
  643.         shr ebx,4                       ; BX = seg of callback area
  644.         mov callbackseg,bx
  645.  
  646.         mov es,bx                       ; ES = seg of callback area
  647.         xor di,di                       ; location within callback seg
  648.  
  649. @@vxr_initl1:
  650.         mov word ptr es:[di],6066h      ; PUSHAD instruction
  651.         mov byte ptr es:[di+2],068h     ; PUSH WORD instruction
  652.         mov word ptr es:[di+3],0        ; immediate 0 used as free flag
  653.         mov word ptr es:[di+5],06866h   ; PUSH DWORD instruction
  654.         mov byte ptr es:[di+11],0b9h    ; MOV CX,? instruction
  655.         mov word ptr es:[di+14],06866h  ; PUSH DWORD instruction
  656.         mov byte ptr es:[di+20],0eah    ; JMP FAR PTR ?:? intruction
  657.         mov word ptr es:[di+21],off callback
  658.         mov word ptr es:[di+23],PMODE_TEXT
  659.  
  660.         add di,25                       ; increment ptr to callback
  661.         dec cl                          ; decrement loop counter
  662.         jnz @@vxr_initl1                ; if more callbacks to do, loop
  663.  
  664.     add di,0fh            ; align next data area on paragraph
  665.     shr di,4
  666.     add bx,di
  667.         mov es,bx                       ; set ES to base of next data area
  668.  
  669. @@vxr_initf3:
  670.  
  671. ;-----------------------------------------------------------------------------
  672.     mov gdtseg,es            ; store segment of GDT
  673.  
  674.         mov ax,es                       ; set GDT base address
  675.         movzx eax,ax
  676.         shl eax,4
  677.         mov gdtbase,eax
  678.  
  679.         mov cx,_pm_selectors            ; set GDT limit
  680.         lea ecx,[8*ecx+8*5+8*SYSSELECTORS-1]
  681.         mov gdtlimit,cx
  682.  
  683.         xor di,di                       ; clear GDT with all 0
  684.         inc cx
  685.         shr cx,1
  686.         xor ax,ax
  687.         rep stos word ptr es:[di]
  688.  
  689.         cmp pmodetype,2                 ; if under VCPI, do VCPI GDT set up
  690.         jne short @@vxr_initf1
  691.  
  692.         pop ax                          ; restore TSS seg from stack
  693.         movzx eax,ax                    ; set up TSS selector in GDT
  694.         shl eax,4
  695.         mov dword ptr es:[SELVCPITSS+2],eax
  696.         mov byte ptr es:[SELVCPITSS],67h
  697.         mov byte ptr es:[SELVCPITSS+5],89h
  698.  
  699.         add eax,64h-4*9                 ; unused part of TSS is also
  700.         mov vcpiswitchstack,eax         ;  temporary switch stack
  701.  
  702.         mov di,SELVCPICODE              ; copy 3 VCPI descriptors from stack
  703.         mov si,sp                       ;  to GDT
  704.         mov cx,4*3
  705.         rep movs word ptr es:[di],word ptr ss:[si]
  706.  
  707.         add sp,8*3                      ; adjust stack
  708.  
  709. @@vxr_initf1:
  710.         mov word ptr es:[SELZERO],0ffffh; set SELZERO descriptor
  711.         mov word ptr es:[SELZERO+5],0df92h
  712.  
  713.         mov word ptr es:[SELCALLBACKDS],0ffffh  ; set callback DS descriptor
  714.     mov word ptr es:[SELCALLBACKDS+5],0df92h
  715.  
  716.         mov word ptr es:[SELREAL],0ffffh; set real mode attributes descriptor
  717.         mov word ptr es:[SELREAL+5],01092h
  718.  
  719.         mov ax,cs                       ; set SELCODE descriptor (PMODE_TEXT)
  720.         mov bx,SELCODE                  ; BX = index to SELCODE descriptor
  721.         mov cx,0ffffh                   ; CX = limit (64k)
  722.         mov dx,109ah                    ; DX = access rights
  723.         call vxr_initsetdsc
  724.  
  725.         mov bx,8*SYSSELECTORS           ; BX = base of free descriptors
  726.         push bx                         ; store selector
  727.  
  728.         mov ax,ss                       ; set caller SS descriptor
  729.         mov dx,5092h
  730.         call vxr_initsetdsc
  731.  
  732.         mov ax,[bp]                     ; set caller DS descriptor
  733.         mov [bp],bx                     ; put DS selector on stack for exit
  734.         call vxr_initsetdsc
  735.  
  736.         push bx                         ; get PSP segment
  737.         mov ah,51h
  738.         int 21h
  739.         mov si,bx
  740.         pop bx
  741.  
  742.         mov fs,si                       ; set caller environment descriptor
  743.         mov ax,fs:[2ch]
  744.         or ax,ax                        ; is environment seg 0?
  745.         jz short @@vxr_initf0           ; if yes, dont convert to descriptor
  746.         mov fs:[2ch],bx                 ; store selector value in PSP
  747.         call vxr_initsetdsc
  748.  
  749. @@vxr_initf0:
  750.         mov ax,si                       ; set caller PSP descriptor
  751.         mov cx,0ffh                     ; limit is 100h bytes
  752.         call vxr_initsetdsc
  753.  
  754. ;-----------------------------------------------------------------------------
  755.         lea ecx,[ebx-8]                 ; CX = ES descriptor, just set
  756.         pop dx                          ; DX = SS descriptor, from stack
  757.         mov ax,SELZERO                  ; AX = DS descriptor, SELZERO
  758.         movzx ebx,sp                    ; EBX = SP, current SP - same stack
  759.         mov si,SELCODE                  ; target CS is SELCODE, same segment
  760.         mov edi,off @@vxr_initf2        ; target EIP
  761.  
  762.         jmp rmtopmswrout                ; jump to mode switch routine
  763.  
  764. @@vxr_initf2:   
  765.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  766.         mov eax,ds:[4*15h]              ; get INT 15h vector
  767.         mov ds:oldint15vector[edi],eax  ; store INT 15h vector
  768.  
  769.         mov esi,cs:rawextmembase        ; ESI = raw base of extended memory
  770.         cmp esi,cs:rawextmemtop         ; is there any raw extended memory?
  771.         jae dvxr_init                   ; if no, go DPMI/VCPI/XMS/raw init
  772.  
  773.         dw 0b866h,off int15,PMODE_TEXT  ; MOV EAX,PMODE_TEXT:offset int15
  774.         mov ds:[4*15h],eax              ; set new INT 15h handler
  775.  
  776.         mov edi,cs:rawextmemtop         ; EDI = raw top of extended memory
  777.         mov eax,edi                     ; EAX = size of extended memory
  778.         sub eax,esi
  779.         sub eax,10h                     ; subtract memory control block size
  780.         mov [edi-16],eax                ; store size in memory control block
  781.         xor eax,eax
  782.         mov [edi-12],eax                ; no next memory control block
  783.         mov [edi-8],eax                 ; no previous memory control block
  784.         mov [edi-4],al                  ; memory block is free
  785.  
  786.         jmp dvxr_init                   ; go to DPMI/VCPI/XMS/raw init tail
  787.  
  788. ;─────────────────────────────────────────────────────────────────────────────
  789. vxr_initsetdsc:                         ; set descriptor for VCPI/XMS/raw init
  790.         movzx eax,ax                    ; EAX = base of segment
  791.         shl eax,4
  792.         mov word ptr es:[bx],cx         ; limit = CX
  793.         mov dword ptr es:[bx+2],eax     ; base address = EAX
  794.         mov word ptr es:[bx+5],dx       ; access rights = DX
  795.         add bx,8                        ; increment descriptor index
  796.         ret
  797.  
  798. ;═════════════════════════════════════════════════════════════════════════════
  799. x_init:                                 ; XMS protected mode init
  800.         push es                         ; preserve ES, INT 2Fh destroys it
  801.  
  802.         mov ax,4310h                    ; get XMS driver address
  803.         int 2fh
  804.  
  805.         mov xms_callip,bx               ; store XMS driver address
  806.         mov xms_callcs,es
  807.  
  808.         pop es                          ; restore ES (buffer segment)
  809.  
  810.         mov ah,3                        ; enable A20
  811.         call dword ptr xms_callip
  812.  
  813.         mov bx,4                        ; error code 0004h in case of error
  814.         cmp ax,1                        ; error enabling A20?
  815.         jc init_done                    ; if yes, exit with error 0004h
  816.  
  817.         mov si,off int31mxrouttbl       ; set XMS memory allocation functions
  818.  
  819. ;─────────────────────────────────────────────────────────────────────────────
  820. xr_init:                                ; XMS/raw common init tail
  821.         push es                         ; preserve ES
  822.  
  823.         push ds                         ; ES = DS for table copy
  824.         pop es
  825.  
  826.         mov di,off int31mrouttbl        ; copy memory allocation function
  827.         mov cx,5                        ;  addresses to table
  828.         rep movs word ptr es:[di],word ptr ds:[si]
  829.  
  830.         pop es                          ; restore ES (buffer segment)
  831.  
  832.         mov rmtopmswrout,off xr_rmtopmsw; set XMS/raw mode switch addresses
  833.         mov pmtormswrout,off xr_pmtormsw
  834.  
  835.         jmp vxr_init                    ; go to VCPI/XMS/raw continue init
  836.  
  837. ;═════════════════════════════════════════════════════════════════════════════
  838. r_init:                                 ; raw protected mode init
  839.         mov ah,88h                      ; how much extended memory free
  840.         int 15h
  841.  
  842.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  843.         or ax,ax                        ; if none, done with raw init
  844.         jz xr_init
  845.  
  846.         movzx eax,ax                    ; convert AX K to ptr to top of mem
  847.         shl eax,10
  848.         add eax,100000h
  849.         mov cs:rawextmemtop,eax
  850.  
  851.         call enablea20                  ; enable A20
  852.  
  853.         push es                         ; preserve ES (buffer segment)
  854.  
  855.         xor cx,cx                       ; ES -> 0 (interrupt vector table)
  856.         mov es,cx
  857.         les bx,dword ptr es:[4*19h]     ; ES:BX -> int vector table
  858.  
  859.         mov eax,100000h                 ; initial free extended memory base
  860.         cmp dword ptr es:[bx+12h],'SIDV'; VDISK memory allocation?
  861.         jne short @@r_initf0            ; if present, get base of free mem
  862.  
  863.         mov eax,dword ptr es:[bx+2ch]   ; get first free byte of extended mem
  864.         add eax,0fh                     ; align on paragraph
  865.         and eax,0fffff0h                ; address is only 24bit
  866.  
  867. @@r_initf0:
  868.         dec cx                          ; ES -> 0ffffh for ext mem addressing
  869.         mov es,cx
  870.  
  871.         cmp dword ptr es:[13h],'SIDV'   ; VDISK memory allocation?
  872.         jne short @@r_initf1            ; if present, get base of free mem
  873.  
  874.         movzx ebx,word ptr es:[2eh]     ; get first free K of extended memory
  875.         shl ebx,10                      ; adjust K to bytes
  876.  
  877.         cmp eax,ebx                     ; pick larger of 2 addresses
  878.         ja short @@r_initf1
  879.  
  880.         mov eax,ebx
  881.  
  882. @@r_initf1:
  883.         pop es                          ; restore ES (buffer segment)
  884.  
  885.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  886.         cmp eax,cs:rawextmemtop         ; any valid free extended memory
  887.         jae xr_init                     ; if none, done with raw init
  888.  
  889.         mov cs:rawextmembase,eax
  890.         mov si,off int31mrrouttbl       ; set raw memory allocation functions
  891.  
  892.         jmp xr_init                     ; go to XMS/raw continue init
  893.  
  894. ;─────────────────────────────────────────────────────────────────────────────
  895. enablea20:                              ; hardware enable gate A20
  896.         pushf
  897.         push fs gs
  898.         cli
  899.  
  900.         xor ax,ax                       ; set A20 test segments 0 and 0ffffh
  901.         mov fs,ax
  902.         dec ax
  903.         mov gs,ax
  904.  
  905.         call enablea20test              ; is A20 already enabled?
  906.         jz short @@enablea20done        ; if yes, done
  907.  
  908.         in al,92h                       ; PS/2 A20 enable
  909.         or al,2
  910.         jmp short $+2
  911.         jmp short $+2
  912.         jmp short $+2
  913.         out 92h,al
  914.  
  915.         call enablea20test              ; is A20 enabled?
  916.         jz short @@enablea20done        ; if yes, done
  917.  
  918.         call enablea20kbwait            ; AT A20 enable
  919.         jnz short @@enablea20f0
  920.  
  921.         mov al,0d1h
  922.         out 64h,al
  923.  
  924.         call enablea20kbwait
  925.         jnz short @@enablea20f0
  926.  
  927.         mov al,0dfh
  928.         out 60h,al
  929.  
  930.         call enablea20kbwait
  931.  
  932. @@enablea20f0:                          ; wait for A20 to enable
  933.         mov cx,800h                     ; do 800h tries
  934.  
  935. @@enablea20l0:
  936.         call enablea20test              ; is A20 enabled?
  937.         jz @@enablea20done              ; if yes, done
  938.  
  939.         in al,40h                       ; get current tick counter
  940.         jmp short $+2
  941.         jmp short $+2
  942.         jmp short $+2
  943.         in al,40h
  944.         mov ah,al
  945.  
  946. @@enablea20l1:                          ; wait a single tick
  947.         in al,40h
  948.         jmp short $+2
  949.         jmp short $+2
  950.         jmp short $+2
  951.         in al,40h
  952.         cmp al,ah
  953.         je @@enablea20l1
  954.  
  955.         loop @@enablea20l0              ; loop for another try
  956.  
  957.         mov bp,sp                       ; error, A20 did not enable
  958.         mov ax,4                        ; error code 4
  959.         mov word ptr [bp+6],off init_done       ; set init_done return address
  960.  
  961. @@enablea20done:
  962.         pop gs fs
  963.         popf
  964.         ret
  965.  
  966. ;-----------------------------------------------------------------------------
  967. enablea20kbwait:                        ; wait for safe to write to 8042
  968.         xor cx,cx
  969. @@enablea20kbwaitl0:
  970.         jmp short $+2
  971.         jmp short $+2
  972.         jmp short $+2
  973.         in al,64h                       ; read 8042 status
  974.         test al,2                       ; buffer full?
  975.         loopnz @@enablea20kbwaitl0      ; if yes, loop
  976.         ret
  977.  
  978. ;-----------------------------------------------------------------------------
  979. enablea20test:                          ; test for enabled A20
  980.         mov al,fs:[0]                   ; get byte from 0:0
  981.         mov ah,al                       ; preserve old byte
  982.         not al                          ; modify byte
  983.         xchg al,gs:[10h]                ; put modified byte to 0ffffh:10h
  984.         cmp ah,fs:[0]                   ; set zero if byte at 0:0 not modified
  985.         mov gs:[10h],al                 ; put back old byte at 0ffffh:10h
  986.         ret                             ; return, zero if A20 enabled
  987.  
  988. ;═════════════════════════════════════════════════════════════════════════════
  989. int15:                                  ; real mode INT 15h handler
  990.         cmp ah,88h                      ; function 88h?
  991.         je short @@int15f0              ; if yes, need to process
  992.  
  993.         jmp cs:oldint15vector           ; no, go on to old INT 15h handler
  994.  
  995. @@int15f0:
  996.         pushf                           ; call old int 15h handler
  997.         call cs:oldint15vector
  998.  
  999.         sub ax,cs:rawextmemused         ; adjust AX by extended memory used
  1000.  
  1001.         push bp                         ; clear carry flag on stack for IRET
  1002.         mov bp,sp
  1003.         and byte ptr [bp+6],0feh
  1004.         pop bp
  1005.  
  1006.         iret                            ; return with new AX extended memory
  1007.  
  1008. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1009. ; PROTECTED MODE KERNEL CODE
  1010. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1011.  
  1012. ;═════════════════════════════════════════════════════════════════════════════
  1013. v_rmtopmsw:                             ; VCPI real to protected switch
  1014.         pushf                           ; store FLAGS
  1015.         cli
  1016.         push cs                         ; DS = PMODE_TEXT
  1017.         pop ds
  1018.         pop tempw0                      ; move FLAGS from stack to temp
  1019.         mov tempw1,ax                   ; store AX (protected mode DS)
  1020.         mov tempw2,si                   ; store SI (protected mode CS)
  1021.         mov esi,vcpistrucaddx           ; ESI = linear addx of VCPI structure
  1022.         mov ax,0de0ch                   ; VCPI switch to protected mode
  1023.         int 67h
  1024. v_rmtopmswpm:
  1025.         mov ss,dx                       ; load protected mode SS:ESP
  1026.         mov esp,ebx
  1027.         mov ds,cs:tempw1                ; load protected mode DS
  1028.         mov es,cx                       ; load protected mode ES
  1029.         xor ax,ax
  1030.         mov fs,ax                       ; load protected mode FS with NULL
  1031.         mov gs,ax                       ; load protected mode GS with NULL
  1032.         pushfd                          ; store EFLAGS
  1033.         mov ax,cs:tempw0                ; move bits 0-11 of old FLAGS onto
  1034.         and ah,0fh                      ;  stack for IRETD
  1035.         mov [esp],ax
  1036.         push cs:tempd1                  ; store protected mode target CS
  1037.         push edi                        ; store protected mode target EIP
  1038.         iretd                           ; go to targed addx in protected mode
  1039.  
  1040. ;═════════════════════════════════════════════════════════════════════════════
  1041. v_pmtormsw:                             ; VCPI protected to real switch
  1042.         pushf                           ; store FLAGS
  1043.         cli
  1044.         push ax                         ; store AX (real mode DS)
  1045.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1046.         movzx ebx,bx                    ; clear high word of EBX, real mode SP
  1047.         movzx edx,dx                    ; clear high word of EDX, real mode SS
  1048.         mov eax,cs:vcpiswitchstack      ; EAX -> top of temporary switch stack
  1049.         mov dword ptr ds:[eax+32],0     ; store real mode GS
  1050.         mov dword ptr ds:[eax+28],0     ; store real mode FS
  1051.         movzx ecx,cx                    ; clear high word of ECX, real mode ES
  1052.         mov ds:[eax+20],ecx             ; store real mode ES
  1053.         pop cx                          ; move real mode DS from protected
  1054.         mov ds:[eax+24],ecx             ;  mode stack to VCPI call stack
  1055.         mov ds:[eax+16],edx             ; store real mode SS
  1056.         mov ds:[eax+12],ebx             ; store real mode SP
  1057.         mov dword ptr ds:[eax+4],PMODE_TEXT             ; store real mode CS
  1058.         mov dword ptr ds:[eax+0],off @@v_pmtormswf0     ; store real mode IP
  1059.         pop bx                          ; restore FLAGS from stack
  1060.         mov ss,cs:selzero               ; SS -> 0 (beginning of memory)
  1061.         mov esp,eax                     ; ESP = stack ptr for VCPI call
  1062.         mov ax,0de0ch                   ; VCPI switch to real mode (V86)
  1063.     call fword ptr cs:vcpi_calleip
  1064. @@v_pmtormswf0:
  1065.         push bx                         ; store old FLAGS
  1066.     push si             ; store target CS in real mode
  1067.     push di             ; store target IP in real mode
  1068.     iret                ; go to target addx in real mode
  1069.  
  1070. ;═════════════════════════════════════════════════════════════════════════════
  1071. xr_rmtopmsw:                            ; XMS/raw real to protected switch
  1072.         pushfd                          ; store EFLAGS
  1073.         cli
  1074.         push ax                         ; store AX (protected mode DS)
  1075.         lidt fword ptr cs:idtlimit      ; load protected mode IDT
  1076.         lgdt fword ptr cs:gdtlimit      ; load protected mode GDT
  1077.         mov eax,cr0                     ; switch to protected mode
  1078.         or al,1
  1079.         mov cr0,eax
  1080.         db 0eah                         ; JMP FAR PTR SELCODE:$+4
  1081.         dw $+4,SELCODE                  ;  (clear prefetch que)
  1082.         pop ds                          ; load protected mode DS
  1083.         mov es,cx                       ; load protected mode ES
  1084.         xor ax,ax
  1085.         mov fs,ax                       ; load protected mode FS with NULL
  1086.         mov gs,ax                       ; load protected mode GS with NULL
  1087.         pop eax
  1088.         mov ss,dx                       ; load protected mode SS:ESP
  1089.         mov esp,ebx
  1090.         and ah,0bfh                     ; set NT=0 in old EFLAGS
  1091.         push ax                         ; set current FLAGS
  1092.         popf
  1093.         push eax                        ; store old EFLAGS
  1094.         push esi                        ; store protected mode target CS
  1095.         push edi                        ; store protected mode target EIP
  1096.         iretd                           ; go to targed addx in protected mode
  1097.  
  1098. ;═════════════════════════════════════════════════════════════════════════════
  1099. xr_pmtormsw:                            ; XMS/raw protected to real switch
  1100.         push cx                         ; store CX (real mode ES)
  1101.         pushf                           ; store FLAGS
  1102.         cli
  1103.         push ax                         ; store AX (real mode DS)
  1104.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1105.         mov ecx,cs:codebase             ; get offset of PMODE_TEXT from 0
  1106.         pop ds:tempw0[ecx]              ; move real mode DS from stack to temp
  1107.         pop ds:tempw1[ecx]              ; move FLAGS from stack to temp
  1108.         pop cx                          ; restore CX (real mode ES)
  1109.         mov ax,SELREAL                  ; load descriptors with real mode seg
  1110.         mov ds,ax                       ;  attributes
  1111.         mov es,ax
  1112.         mov fs,ax
  1113.         mov gs,ax
  1114.         mov ss,ax                       ; load descriptor with real mode attr
  1115.         movzx esp,bx                    ; load real mode SP, high word 0
  1116.         lidt fword ptr cs:rmidtlimit    ; load real mode IDT
  1117.         mov eax,cr0                     ; switch to real mode
  1118.         and al,0feh
  1119.         mov cr0,eax
  1120.         db 0eah                         ; JMP FAR PTR PMODE_TEXT:$+4
  1121.         dw $+4,PMODE_TEXT               ;  (clear prefetch que)
  1122.         mov ss,dx                       ; load real mode SS
  1123.         mov ds,cs:tempw0                ; load real mode DS
  1124.         mov es,cx                       ; load real mode ES
  1125.         xor ax,ax
  1126.         mov fs,ax                       ; load real mode FS with NULL
  1127.         mov gs,ax                       ; load real mode GS with NULL
  1128.         push cs:tempw1                  ; store old FLAGS
  1129.         push si                         ; store real mode target CS
  1130.         push di                         ; store real mode target IP
  1131.         iret                            ; go to target addx in real mode
  1132.  
  1133. ;═════════════════════════════════════════════════════════════════════════════
  1134. vxr_saverestorerm:                      ; VCPI/XMS/raw save/restore status
  1135.         retf                            ; no save/restore needed, 16bit RETF
  1136.  
  1137. ;═════════════════════════════════════════════════════════════════════════════
  1138. vxr_saverestorepm:                      ; VCPI/XMS/raw save/restore status
  1139.         db 66h,0cbh                     ; no save/restore needed, 32bit RETF
  1140.  
  1141. ;═════════════════════════════════════════════════════════════════════════════
  1142. critical_error:                         ; some unrecoverable error
  1143.         cli                             ; make sure we are not interrupted
  1144.         in al,61h                       ; beep
  1145.         or al,3
  1146.         out 61h,al
  1147.         jmp $                           ; now hang
  1148.  
  1149. ;═════════════════════════════════════════════════════════════════════════════
  1150. callback:                               ; real mode callback handler
  1151.         mov ax,sp                       ; preserve SS:SP for callback
  1152.         push ss
  1153.         push ax
  1154.  
  1155.         push gs fs ds es                ; preserve real mode regs for callback
  1156.         pushf                           ; preserve FLAGS for callback
  1157.  
  1158.         cli
  1159.         cld
  1160.  
  1161.         mov ebp,cs:pmstacktop           ; EBP = ESP for protected mode
  1162.  
  1163.         mov ebx,ebp                     ; set EBX to next stack location
  1164.         sub ebx,cs:pmstacklen
  1165.         mov cs:pmstacktop,ebx           ; update ptr for possible reenterancy
  1166.  
  1167.         cmp ebx,cs:pmstackbase          ; exceeded protected mode stack space?
  1168.         jb critical_error               ; if yes, critical error (hang)
  1169.  
  1170.         xor eax,eax                     ; EAX = base address of SS
  1171.         mov ax,ss
  1172.         shl eax,4
  1173.  
  1174.     movzx ebx,sp            ; EBX = current linear SS:SP
  1175.         add ebx,eax
  1176.  
  1177.     mov es,cs:gdtseg        ; set for protected mode callback DS
  1178.     or eax,92000000h        ;  base address in GDT
  1179.         mov es:[SELCALLBACKDS+2],eax
  1180.  
  1181.         mov ax,SELZERO                  ; DS selector for protected mode
  1182.         mov dx,ax                       ; SS selector = DS selector
  1183.         mov si,SELCODE                  ; target protected mode CS:EIP
  1184.         mov edi,offset @@callbackf0
  1185.  
  1186.         jmp cs:rmtopmswrout             ; go to protected mode
  1187.  
  1188. @@callbackf0:
  1189.         mov edi,[esp+14]                ; EDI -> register structure from stack
  1190.  
  1191.         lea esi,[esp+24]                ; copy general registers from stack
  1192.         mov ecx,8                       ;  to register structure
  1193.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1194.  
  1195.         mov esi,esp                     ; copy FLAGS, ES, DS, FG, and GS
  1196.         movs word ptr es:[edi],word ptr ds:[esi]
  1197.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1198.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1199.  
  1200.         lods dword ptr ds:[esi]         ; EAX = real mode SS:SP from stack
  1201.         add ax,42                       ; adjust SP for stuff on stack
  1202.         mov es:[edi+4],eax              ; put in register structure
  1203.  
  1204.         mov ds,cs:selcallbackds         ; DS = callback DS selector
  1205.         sub edi,42                      ; EDI -> register structure
  1206.         movzx esi,ax                    ; ESI = old real mode SP
  1207.         xchg esp,ebp                    ; ESP = protected mode stack
  1208.  
  1209.         pushfd                          ; push flags for IRETD from callback
  1210.         db 66h                          ; push 32bit CS for IRETD
  1211.         push cs
  1212.         dw 6866h,@@callbackf1,0         ; push 32bit EIP for IRETD
  1213.  
  1214.         movzx eax,word ptr [ebp+22]     ; EAX = target CS of callback
  1215.         push eax                        ; push 32bit CS for RETF to callback
  1216.         push dword ptr [ebp+18]         ; push 32bit EIP for retf
  1217.  
  1218.         db 66h                          ; 32bit RETF to callback
  1219.         retf
  1220.  
  1221. @@callbackf1:
  1222.         cli
  1223.         cld
  1224.  
  1225.         push es                         ; DS:ESI = register structure
  1226.         pop ds
  1227.         mov esi,edi
  1228.  
  1229.         mov es,cs:selzero               ; ES -> 0 (beginning of memory)
  1230.  
  1231.         movzx ebx,word ptr [esi+2eh]    ; EBX = real mode SP from structure
  1232.         movzx edx,word ptr [esi+30h]    ; EDX = real mode SS from structure
  1233.         sub bx,42                       ; subtract size of vars to be put
  1234.  
  1235.         mov ebp,[esi+0ch]               ; EBP = pushed ESP from real mode
  1236.         mov bp,bx                       ; EBP = old high & new low word of ESP
  1237.  
  1238.         lea edi,[edx*4]                 ; EDI -> real mode base of stack
  1239.         lea edi,[edi*4+ebx]             ;  of vars to be stored
  1240.  
  1241.         mov ecx,8                       ; copy general registers to stack
  1242.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1243.  
  1244.         mov eax,[esi+6]                 ; EAX = return FS and GS for real mode
  1245.         mov es:[edi],eax                ; store on real mode stack for return
  1246.  
  1247.         mov ax,[esi]                    ; AX = return FLAGS for real mode
  1248.         mov es:[edi+8],ax               ; store on real mode stack for return
  1249.         mov eax,[esi+10]                ; EAX = return CS:IP for real mode
  1250.         mov es:[edi+4],eax              ; store on real mode stack for return
  1251.  
  1252.         mov ax,[esi+4]                  ; AX = return DS for real mode
  1253.         mov cx,[esi+2]                  ; CX = return ES for real mode
  1254.  
  1255.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1256.         mov di,off @@callbackf2
  1257.  
  1258.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1259.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1260.  
  1261. @@callbackf2:
  1262.         mov esp,ebp                     ; restore total ESP, old high word
  1263.  
  1264.         mov eax,cs:pmstacklen           ; restore top of protected mode stack
  1265.         add cs:pmstacktop,eax
  1266.  
  1267.         popad                           ; get callback return general regs
  1268.         pop fs gs                       ; get callback return FS and GS values
  1269.         iret                            ; go to callback return CS:IP
  1270.  
  1271. ;═════════════════════════════════════════════════════════════════════════════
  1272. intrmatrix:                ; INT redirectors for all INTs
  1273.         db 100h dup(0cch)               ; 100h INT 3s
  1274.  
  1275. ;═════════════════════════════════════════════════════════════════════════════
  1276. intr:                                   ; general interrupt redirector
  1277.         cmp word ptr [esp+4],SELCODE    ; INT redirection or internal INT 3?
  1278.         je short @@intrf0               ; if not INT 3, jump to redirection
  1279.  
  1280.         jmp fword ptr cs:int3vector     ; INT 3, jump to INT 3 vector
  1281.  
  1282. @@intrf0:
  1283.         mov [esp+8],eax                 ; store EAX for later POPAD
  1284.         mov eax,[esp]                   ; get address in redirection matrix
  1285.         add esp,8                       ; discard EIP and CS from INT 3
  1286.         push ecx edx ebx esp ebp esi edi; store rest of registers for POPAD
  1287.         push ds es fs gs
  1288.  
  1289.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1290.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1291.  
  1292.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1293.         movzx ebp,dx                    ; EBP -> top of real mode stack
  1294.         shl ebp,4
  1295.  
  1296.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1297.         sub dx,bx                       ; adjust DX to next stack location
  1298.         mov ds:rmstacktop[edi],dx       ; update ptr for possible reenterancy
  1299.         shl bx,4                        ; set real mode SP to top of stack
  1300.  
  1301.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1302.         jb critical_error               ; if yes, critical error (hang)
  1303.  
  1304.         mov ds:[ebp-2],ss               ; store SS:ESP on real mode stack
  1305.         mov ds:[ebp-6],esp
  1306.  
  1307.         sub ax,off intrmatrix+1         ; AX = int number
  1308.         mov ah,al                       ; AH = high 5 bits of int number
  1309.         and ah,0f8h
  1310.  
  1311.         cmp ah,cs:picslave              ; high IRQ?
  1312.         je short intrirq                ; if yes, do IRQ
  1313.         cmp ah,cs:picmaster             ; low IRQ?
  1314.         jne short intrint               ; if no, do INT (with general regs)
  1315.  
  1316. ;-----------------------------------------------------------------------------
  1317. intrirq:                                ; an IRQ redirection
  1318.         mov ds:@@intrirqintnum[edi],al  ; modify code with interrupt number
  1319.  
  1320.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1321.         mov di,off @@intrirqf0
  1322.         sub bx,6                        ; adjust real mode SP for stored vars
  1323.  
  1324.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1325.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1326.  
  1327. @@intrirqf0:
  1328.         db 0cdh                         ; INT @@intrirqintnum
  1329. @@intrirqintnum db      ?
  1330.  
  1331.         mov ax,SELZERO                  ; DS selector value for protected mode
  1332.         mov cx,ax                       ; ES selector value for protected mode
  1333.         pop ebx                         ; get protected mode SS:ESP from stack
  1334.         pop dx
  1335.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1336.         mov edi,off @@intrirqf1
  1337.  
  1338.         jmp cs:rmtopmswrout             ; go back to protected mode
  1339.  
  1340. @@intrirqf1:
  1341.         mov edi,cs:codebase             ; restore top of real mode stack
  1342.         mov ax,cs:_pm_rmstacklen
  1343.         add ds:rmstacktop[edi],ax
  1344.  
  1345.         pop gs fs es ds                 ; restore all registers
  1346.         popad
  1347.         iretd
  1348.  
  1349. ;-----------------------------------------------------------------------------
  1350. intrint:                                ; an INT redirection
  1351.         mov ds:@@intrintintnum[edi],al  ; modify code with interrupt number
  1352.  
  1353.         mov es,cs:selzero               ; copy registers from protected mode
  1354.         lea edi,[ebp-26h]               ;  stack to real mode stack
  1355.         lea esi,[esp+8]
  1356.         mov ecx,8
  1357.         cld
  1358.         rep movs dword ptr es:[edi],dword ptr ss:[esi]
  1359.  
  1360.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1361.         mov di,off @@intrintf0
  1362.         sub bx,26h                      ; adjust real mode SP for stored vars
  1363.  
  1364.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1365.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1366.  
  1367. @@intrintf0:
  1368.         popad                           ; load regs with int call values
  1369.  
  1370.         db 0cdh                         ; INT @@intrirqintnum
  1371. @@intrintintnum db      ?
  1372.  
  1373.         pushad                          ; store registers on stack
  1374.         pushf                           ; store flags on stack
  1375.         cli
  1376.  
  1377.         xor eax,eax                     ; EAX = linear ptr to SS
  1378.         mov ax,ss
  1379.         shl eax,4
  1380.         movzx ebp,sp                    ; EBP = SP
  1381.  
  1382.         mov ebx,[bp+22h]                ; get protected mode SS:ESP from stack
  1383.         mov dx,[bp+26h]
  1384.  
  1385.         add ebp,eax                     ; EBP -> stored regs on stack
  1386.  
  1387.         mov ax,SELZERO                  ; DS selector value for protected mode
  1388.         mov cx,ax                       ; ES selector value for protected mode
  1389.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1390.         mov edi,off @@intrintf1
  1391.  
  1392.         jmp cs:rmtopmswrout             ; go back to protected mode
  1393.  
  1394. @@intrintf1:
  1395.         mov edi,cs:codebase             ; restore top of real mode stack
  1396.         mov ax,cs:_pm_rmstacklen
  1397.         add ds:rmstacktop[edi],ax
  1398.  
  1399.         mov ax,ds:[ebp]                 ; move return FLAGS from real mode
  1400.         and ax,8d5h                     ;  stack to protected mode stack
  1401.         mov bx,[esp+30h]
  1402.         and bx,not 8d5h
  1403.         or ax,bx
  1404.         mov [esp+30h],ax
  1405.  
  1406.         mov edi,ds:[ebp+2]              ; restore return registers from real
  1407.         mov esi,ds:[ebp+6]              ;  mode stack
  1408.         mov ebx,ds:[ebp+18]
  1409.         mov edx,ds:[ebp+22]
  1410.         mov ecx,ds:[ebp+26]
  1411.         mov eax,ds:[ebp+30]
  1412.         mov ebp,ds:[ebp+10]
  1413.  
  1414.         pop gs fs es ds                 ; restore segment regs
  1415.         add esp,20h                     ; skip old general registers on stack
  1416.         iretd
  1417.  
  1418. ;═════════════════════════════════════════════════════════════════════════════
  1419. int21:                                  ; watch for INT 21h AH=4Ch
  1420.         cmp ah,4ch                      ; AH = 4Ch?
  1421.         jne intrmatrix+21h              ; if no, go to INT 21h redirection
  1422.  
  1423.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1424.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1425.  
  1426.         mov ebx,cs:oldint15vector       ; put back old INT 15h handler
  1427.         mov ds:[4*15h],ebx
  1428.  
  1429.         jmp intrmatrix+21h              ; go to INT 21h redirection
  1430.  
  1431. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1432. ; INT 31h INTERFACE
  1433. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1434.  
  1435. ;═════════════════════════════════════════════════════════════════════════════
  1436. int31:                                  ; protected mode INT 31h handler
  1437.         cli
  1438.         cld
  1439.         push ds es fs gs                ; push regs needed
  1440.         pushad
  1441.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1442.  
  1443.         push bx
  1444.         mov bx,(INT31FUNCNUM - 1) * 2   ; number of functions to check
  1445. @@int31l0:
  1446.         cmp ax,cs:int31functbl[bx]      ; found function value?
  1447.         jne short @@int31l0c
  1448.  
  1449.         mov bx,cs:int31routtbl[bx]      ; yes, go to appropriate handler
  1450.         xchg bx,[esp]
  1451.         ret
  1452.  
  1453. @@int31l0c:
  1454.         sub bx,2                        ; no, continue loop
  1455.         jnc @@int31l0
  1456.  
  1457.         pop bx                          ; no function found
  1458.         jmp int31fail8001               ; error 8001h
  1459.  
  1460. ;-----------------------------------------------------------------------------
  1461. int31fail8024:                          ; INT 31h return fail with error 8024h
  1462.         mov word ptr [esp+28],8024h     ; set AX on stack to 8024h for POPAD
  1463.         jmp short int31fail
  1464.  
  1465. ;-----------------------------------------------------------------------------
  1466. int31fail8023:                          ; INT 31h return fail with error 8023h
  1467.         mov word ptr [esp+28],8023h     ; set AX on stack to 8023h for POPAD
  1468.         jmp short int31fail
  1469.  
  1470. ;-----------------------------------------------------------------------------
  1471. int31fail8022:                          ; INT 31h return fail with error 8022h
  1472.         mov word ptr [esp+28],8022h     ; set AX on stack to 8022h for POPAD
  1473.         jmp short int31fail
  1474.  
  1475. ;-----------------------------------------------------------------------------
  1476. int31fail8021:                          ; INT 31h return fail with error 8021h
  1477.         mov word ptr [esp+28],8021h     ; set AX on stack to 8021h for POPAD
  1478.         jmp short int31fail
  1479.  
  1480. ;-----------------------------------------------------------------------------
  1481. int31fail8016:                          ; INT 31h return fail with error 8016h
  1482.         mov word ptr [esp+28],8016h     ; set AX on stack to 8016h for POPAD
  1483.         jmp short int31fail
  1484.  
  1485. ;-----------------------------------------------------------------------------
  1486. int31fail8015:                          ; INT 31h return fail with error 8015h
  1487.         mov word ptr [esp+28],8015h     ; set AX on stack to 8015h for POPAD
  1488.         jmp short int31fail
  1489.  
  1490. ;-----------------------------------------------------------------------------
  1491. int31fail8013:                          ; INT 31h return fail with error 8013h
  1492.         mov word ptr [esp+28],8013h     ; set AX on stack to 8013h for POPAD
  1493.         jmp short int31fail
  1494.  
  1495. ;-----------------------------------------------------------------------------
  1496. int31fail8012:                          ; INT 31h return fail with error 8012h
  1497.         mov word ptr [esp+28],8012h     ; set AX on stack to 8012h for POPAD
  1498.         jmp short int31fail
  1499.  
  1500. ;-----------------------------------------------------------------------------
  1501. int31fail8011:                          ; INT 31h return fail with error 8011h
  1502.         mov word ptr [esp+28],8011h     ; set AX on stack to 8011h for POPAD
  1503.         jmp short int31fail
  1504.  
  1505. ;-----------------------------------------------------------------------------
  1506. int31fail8010:                          ; INT 31h return fail with error 8010h
  1507.         mov word ptr [esp+28],8010h     ; set AX on stack to 8010h for POPAD
  1508.         jmp short int31fail
  1509.  
  1510. ;-----------------------------------------------------------------------------
  1511. int31fail8001:                          ; INT 31h return fail with error 8001h
  1512.         mov word ptr [esp+28],8001h     ; set AX on stack to 8001h for POPAD
  1513.         jmp short int31fail
  1514.  
  1515. ;-----------------------------------------------------------------------------
  1516. int31failcx:                            ; INT 31h return fail with CX,AX
  1517.         mov word ptr [esp+24],cx        ; put CX onto stack for POPAD
  1518.  
  1519. ;-----------------------------------------------------------------------------
  1520. int31failax:                            ; INT 31h return fail with AX
  1521.         mov word ptr [esp+28],ax        ; put AX onto stack for POPAD
  1522.  
  1523. ;-----------------------------------------------------------------------------
  1524. int31fail:                              ; INT 31h return fail, pop all regs
  1525.         popad
  1526.         pop gs fs es ds
  1527.  
  1528. ;-----------------------------------------------------------------------------
  1529. int31failnopop:                         ; INT 31h return fail with carry set
  1530.         or byte ptr [esp+8],1           ; set carry in EFLAGS on stack
  1531.         iretd
  1532.  
  1533. ;-----------------------------------------------------------------------------
  1534. int31okedx:                             ; INT 31h return ok with EDX,CX,AX
  1535.         mov [esp+20],edx                ; put EDX onto stack for POPAD
  1536.         jmp short int31okcx
  1537.  
  1538. ;-----------------------------------------------------------------------------
  1539. int31okdx:                              ; INT 31h return ok with DX,CX,AX
  1540.         mov [esp+20],dx                 ; put DX onto stack for POPAD
  1541.         jmp short int31okcx
  1542.  
  1543. ;-----------------------------------------------------------------------------
  1544. int31oksinoax:                          ; INT 31h return ok SI,DI,BX,CX
  1545.         mov ax,[esp+28]                 ; get old value of AX for restore
  1546.  
  1547. ;-----------------------------------------------------------------------------
  1548. int31oksi:                              ; INT 31h return ok SI,DI,BX,CX,AX
  1549.         mov [esp+4],si                  ; put SI onto stack for POPAD
  1550.         mov [esp],di                    ; put DI onto stack for POPAD
  1551.         mov [esp+16],bx                 ; put BX onto stack for POPAD
  1552.  
  1553. ;-----------------------------------------------------------------------------
  1554. int31okcx:                              ; INT 31h return ok with CX,AX
  1555.         mov [esp+24],cx                 ; put CX onto stack for POPAD
  1556.  
  1557. ;-----------------------------------------------------------------------------
  1558. int31okax:                              ; INT 31h return ok with AX
  1559.         mov [esp+28],ax                 ; put AX onto stack for POPAD
  1560.  
  1561. ;-----------------------------------------------------------------------------
  1562. int31ok:                                ; INT 31h return ok, pop all regs
  1563.         popad
  1564.         pop gs fs es ds
  1565.  
  1566. ;-----------------------------------------------------------------------------
  1567. int31oknopop:                           ; INT 31h return ok with carry clear
  1568.         and byte ptr [esp+8],0feh       ; clear carry in EFLAGS on stack
  1569.         iretd
  1570.  
  1571. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1572. ; DESCRIPTOR FUNCTIONS
  1573. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1574.  
  1575. ;-----------------------------------------------------------------------------
  1576. int31testsel:                           ; test for valid selector BX
  1577.         pop bp                          ; pop return address
  1578.  
  1579.         cmp bx,cs:gdtlimit              ; selector BX out of range?
  1580.         ja int31fail8022                ; if yes, fail with error 8022h
  1581.  
  1582.         mov edi,cs:gdtbase              ; get base of GDT
  1583.         and bl,0f8h                     ; mask offset table index and RPL
  1584.         movzx ebx,bx                    ; EBX = selector index
  1585.         test byte ptr ds:[edi+ebx+6],10h; is descriptor used?
  1586.         jz int31fail8022                ; if descriptor not used, fail 8022h
  1587.  
  1588.         jmp bp                          ; return ok
  1589.  
  1590. ;-----------------------------------------------------------------------------
  1591. int31testaccess:                        ; test access bits in CX
  1592.         pop bp                          ; pop return address
  1593.  
  1594.         test ch,20h                     ; test MUST BE 0 bit in CH
  1595.         jnz int31fail8021               ; if not 0, error 8021h
  1596.  
  1597.         test cl,90h                     ; test present and MUST BE 1 bits
  1598.         jz int31fail8021                ; if both 0, error 8021h
  1599.         jpo int31fail8021               ; if unequal, error 8021h
  1600.  
  1601.         test cl,60h                     ; test DPL
  1602.         jnz int31fail8021               ; if not 0, error 8021h
  1603.  
  1604.         test cl,8                       ; if code, more tests needed
  1605.         jz short @@int31testselok       ; if data, skip code tests
  1606.  
  1607.         test cl,6                       ; test conforming and readable bits
  1608.         jz int31fail8021                ; if both 0, error 8021h
  1609.         jpe int31fail8021               ; if equal, error 8021h
  1610.  
  1611. @@int31testselok:
  1612.         jmp bp                          ; return ok
  1613.  
  1614. ;─────────────────────────────────────────────────────────────────────────────
  1615. int310000:                              ; allocate descriptors
  1616.         or cx,cx                        ; if CX = 0, error 8021h
  1617.         jz int31fail8021
  1618.  
  1619.         mov edx,cs:gdtbase              ; get base of GDT
  1620.         movzx eax,cs:gdtlimit           ; EAX = last selector index
  1621.         and al,0f8h
  1622.  
  1623.         mov bx,cx                       ; BX = number of selectors to find
  1624. @@int310000l0:
  1625.         test byte ptr ds:[edx+eax+6],10h; is descriptor used?
  1626.         jnz short @@int310000l0f0
  1627.  
  1628.         dec bx                          ; found free descriptor, dec counter
  1629.         jnz short @@int310000l0f1       ; continue if need to find more
  1630.  
  1631.         mov ebx,eax                     ; found all descriptors requested
  1632. @@int310000l1:
  1633.         mov dword ptr ds:[edx+ebx],0    ; set entire new descriptor
  1634.         mov dword ptr ds:[edx+ebx+4],109200h
  1635.         add bx,8                        ; increment selector index
  1636.         dec cx                          ; dec counter of descriptors to mark
  1637.         jnz @@int310000l1               ; loop if more to mark
  1638.  
  1639.         jmp int31okax                   ; return ok, with AX
  1640.  
  1641. @@int310000l0f0:
  1642.         mov bx,cx                       ; reset number of selectors to find
  1643.  
  1644. @@int310000l0f1:
  1645.         sub ax,8                        ; dec current selector counter
  1646.         cmp ax,8*SYSSELECTORS           ; more descriptors to go?
  1647.         jae @@int310000l0               ; if yes, loop
  1648.  
  1649.         jmp int31fail8011               ; did not find descriptors
  1650.  
  1651. ;─────────────────────────────────────────────────────────────────────────────
  1652. int310001:                              ; free descriptor
  1653.         call int31testsel               ; test for valid selector BX
  1654.  
  1655.         and byte ptr ds:[edi+ebx+6],0efh; mark descriptor as free
  1656.  
  1657.         mov cx,4                        ; zero any segregs loaded with BX
  1658.         lea ebp,[esp+32]                ; EBP -> selectors on stack
  1659. @@int310001l0:
  1660.         cmp word ptr [ebp],bx           ; selector = BX?
  1661.         jne short @@int310001l0f0       ; if no, continue loop
  1662.  
  1663.         mov word ptr [ebp],0            ; zero selector on stack
  1664.  
  1665. @@int310001l0f0:
  1666.         add ebp,2                       ; increment selector ptr
  1667.         loop @@int310001l0              ; loop
  1668.  
  1669.         jmp int31ok                     ; return ok
  1670.  
  1671. ;─────────────────────────────────────────────────────────────────────────────
  1672. int310003:                              ; get selector increment value
  1673.         mov ax,8                        ; selector increment value is 8
  1674.         jmp int31okax                   ; return ok, with AX
  1675.  
  1676. ;─────────────────────────────────────────────────────────────────────────────
  1677. int310006:                              ; get segment base address
  1678.         call int31testsel               ; test for valid selector BX
  1679.  
  1680.         mov dx,word ptr ds:[edi+ebx+2]  ; low word of 32bit linear address
  1681.         mov cl,byte ptr ds:[edi+ebx+4]  ; high word of 32bit linear address
  1682.         mov ch,byte ptr ds:[edi+ebx+7]
  1683.  
  1684.         jmp int31okdx                   ; return ok, with DX, CX, AX
  1685.  
  1686. ;─────────────────────────────────────────────────────────────────────────────
  1687. int310007:                              ; set segment base address
  1688.         call int31testsel               ; test for valid selector BX
  1689.  
  1690.         mov word ptr ds:[edi+ebx+2],dx  ; low word of 32bit linear address
  1691.         mov byte ptr ds:[edi+ebx+4],cl  ; high word of 32bit linear address
  1692.         mov byte ptr ds:[edi+ebx+7],ch
  1693.  
  1694.         jmp int31ok                     ; return ok
  1695.  
  1696. ;─────────────────────────────────────────────────────────────────────────────
  1697. int310008:                              ; set segment limit
  1698.         call int31testsel               ; test for valid selector BX
  1699.  
  1700.         cmp cx,0fh                      ; limit greater than 1M?
  1701.         jbe short @@int310008f0
  1702.  
  1703.         mov ax,dx                       ; yup, limit greater than 1M
  1704.         and ax,0fffh
  1705.         cmp ax,0fffh                    ; low 12 bits set?
  1706.         jne int31fail8021               ; if no, error 8021h
  1707.  
  1708.         shrd dx,cx,12                   ; DX = low 16 bits of page limit
  1709.         shr cx,12                       ; CL = high 4 bits of page limit
  1710.         or cl,80h                       ; set granularity bit in CL
  1711.  
  1712. @@int310008f0:
  1713.         mov word ptr ds:[edi+ebx],dx    ; put low word of limit
  1714.         and byte ptr ds:[edi+ebx+6],70h ; mask off G and high nybble of limit
  1715.         or byte ptr ds:[edi+ebx+6],cl   ; put high nybble of limit
  1716.  
  1717.         jmp int31ok                     ; return ok
  1718.  
  1719. ;─────────────────────────────────────────────────────────────────────────────
  1720. int310009:                              ; set descriptor access rights
  1721.         call int31testsel               ; test for valid selector BX
  1722.  
  1723.         call int31testaccess            ; test access bits in CX
  1724.  
  1725.         or ch,10h                       ; set AVL bit, descriptor used
  1726.         and ch,0f0h                     ; mask off low nybble of CH
  1727.         and byte ptr ds:[edi+ebx+6],0fh ; mask off high nybble access rights
  1728.         or byte ptr ds:[edi+ebx+6],ch   ; or in high access rights byte
  1729.         mov byte ptr ds:[edi+ebx+5],cl  ; put low access rights byte
  1730.  
  1731.         jmp int31ok                     ; return ok
  1732.  
  1733. ;─────────────────────────────────────────────────────────────────────────────
  1734. int31000a:                              ; create alias descriptor
  1735.         call int31testsel               ; test for valid selector BX
  1736.  
  1737.         mov ax,0000h                    ; allocate descriptor
  1738.         mov cx,1
  1739.         int 31h
  1740.         jc int31fail8011                ; if failed, descriptor unavailable
  1741.  
  1742.         push ax                         ; preserve allocated selector
  1743.  
  1744.         push ds                         ; copy descriptor and set type data
  1745.         pop es
  1746.         movzx edi,ax                    ; EDI = target selector
  1747.         mov esi,cs:gdtbase              ; ESI -> GDT
  1748.         add edi,esi                     ; adjust to target descriptor in GDT
  1749.         add esi,ebx                     ; adjust to source descriptor in GDT
  1750.  
  1751.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1752.         lods dword ptr ds:[esi]
  1753.         mov ah,92h                      ; set descriptor type - R/W up data
  1754.         stos dword ptr es:[edi]
  1755.  
  1756.         pop ax                          ; restore allocated selector
  1757.  
  1758.         jmp int31okax                   ; return ok, with AX
  1759.  
  1760. ;─────────────────────────────────────────────────────────────────────────────
  1761. int31000b:                              ; get descriptor
  1762.         call int31testsel               ; test for valid selector BX
  1763.  
  1764.         lea esi,[edi+ebx]               ; ESI -> descriptor in GDT
  1765.         mov edi,[esp]                   ; get EDI buffer ptr from stack
  1766.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1767.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1768.  
  1769.         jmp int31ok                     ; return ok
  1770.  
  1771. ;─────────────────────────────────────────────────────────────────────────────
  1772. int31000c:                              ; set descriptor
  1773.         call int31testsel               ; test for valid selector BX
  1774.  
  1775.         mov esi,[esp]                   ; ESI = EDI buffer ptr from stack
  1776.         mov cx,es:[esi+5]               ; get access rights from descriptor
  1777.         call int31testaccess            ; test access bits in CX
  1778.  
  1779.         push ds                         ; swap DS and ES, target and source
  1780.         push es
  1781.         pop ds
  1782.         pop es
  1783.  
  1784.         add edi,ebx                     ; adjust EDI to descriptor in GDT
  1785.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1786.         lods dword ptr ds:[esi]
  1787.         or eax,100000h                  ; set descriptor AVL bit
  1788.         stos dword ptr es:[edi]
  1789.  
  1790.         jmp int31ok                     ; return ok
  1791.  
  1792. ;─────────────────────────────────────────────────────────────────────────────
  1793. int31000e:                              ; get multiple descriptors
  1794.         mov ax,000bh                    ; function 000bh, get descriptor
  1795.  
  1796. ;-----------------------------------------------------------------------------
  1797. int31000ef:                             ; common to funcions 000eh and 000fh
  1798.         or cx,cx                        ; if CX = 0, return ok immediately
  1799.         jz int31ok
  1800.  
  1801.         mov dx,cx                       ; DX = number of descriptors
  1802.         xor cx,cx                       ; CX = successful counter
  1803. @@int31000efl0:
  1804.         mov bx,es:[edi]                 ; BX = selector to get
  1805.         add edi,2
  1806.  
  1807.         int 31h                         ; get/set descriptor
  1808.         jc int31failcx                  ; if error, fail with AX and CX
  1809.  
  1810.         add edi,8                       ; increment descriptor ptr
  1811.         inc cx                          ; increment successful copy counter
  1812.         dec dx                          ; decrement loop counter
  1813.         jnz @@int31000efl0              ; if more descriptors to go, loop
  1814.  
  1815.         jmp int31ok                     ; return ok
  1816.  
  1817. ;─────────────────────────────────────────────────────────────────────────────
  1818. int31000f:                              ; set multiple descriptors
  1819.         mov ax,000ch                    ; function 000ch, set descriptor
  1820.  
  1821.         jmp int31000ef                  ; go to common function
  1822.  
  1823. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1824. ; INTERRUPT FUNCTIONS
  1825. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1826.  
  1827. ;─────────────────────────────────────────────────────────────────────────────
  1828. int310200:                              ; get real mode interrupt vector
  1829.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1830.         mov dx,ds:[ebx*4]               ; load real mode vector offset
  1831.         mov cx,ds:[ebx*4+2]             ; load real mode vector segment
  1832.  
  1833.         jmp int31okdx                   ; return ok, with AX, CX, DX
  1834.  
  1835. ;─────────────────────────────────────────────────────────────────────────────
  1836. int310201:                              ; set real mode interrupt vector
  1837.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1838.         mov ds:[ebx*4],dx               ; set real mode vector offset
  1839.         mov ds:[ebx*4+2],cx             ; set real mode vector segment
  1840.  
  1841.         jmp int31ok                     ; return ok
  1842.  
  1843. ;─────────────────────────────────────────────────────────────────────────────
  1844. int310204:                              ; get protected mode interrupt vector
  1845.         cmp bl,3                        ; INT 3 vector?
  1846.         je short @@int310204f00         ; if yes, go to special INT 3 handling
  1847.  
  1848.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1849.         shl ebx,3                       ; adjust for location in IDT
  1850.         add ebx,cs:idtbase              ; add base of IDT
  1851.  
  1852.         mov edx,dword ptr ds:[ebx+4]    ; get high word of offset
  1853.         mov dx,word ptr ds:[ebx]        ; get low word of offset
  1854.         mov cx,word ptr ds:[ebx+2]      ; get selector
  1855.  
  1856.         jmp int31okedx                  ; return ok, with AX, CX, EDX
  1857.  
  1858. @@int310204f00:
  1859.         mov edx,dword ptr cs:int3vector[0]      ; get offset of INT 3
  1860.         mov cx,word ptr cs:int3vector[4]        ; get selector of INT 3
  1861.  
  1862.         jmp int31okedx                  ; return ok, with AX, CX, EDX
  1863.  
  1864. ;─────────────────────────────────────────────────────────────────────────────
  1865. int310205:                              ; set protected mode interrupt vector
  1866.         xchg bx,cx                      ; swap int number with int selector
  1867.         call int31testsel               ; test for valid selector BX
  1868.  
  1869.         cmp cl,3                        ; INT 3 vector?
  1870.         je short @@int310205f00         ; if yes, go to special INT 3 handling
  1871.  
  1872.         movzx ecx,cl                    ; ECX = CL (interrupt number)
  1873.         shl ecx,3                       ; adjust for location in IDT
  1874.         add ecx,cs:idtbase              ; add base of IDT
  1875.  
  1876.         mov word ptr ds:[ecx],dx        ; set low word of offset
  1877.         shr edx,16
  1878.         mov word ptr ds:[ecx+6],dx      ; set high word of offset
  1879.         mov word ptr ds:[ecx+2],bx      ; set selector
  1880.  
  1881.         jmp int31ok                     ; return ok
  1882.  
  1883. @@int310205f00:
  1884.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1885.  
  1886.         mov dword ptr ds:int3vector[edi+0],edx  ; set offset of INT 3
  1887.         mov word ptr ds:int3vector[edi+4],bx    ; set selector of INT 3
  1888.  
  1889.         jmp int31ok                     ; return ok
  1890.  
  1891. ;─────────────────────────────────────────────────────────────────────────────
  1892. int310900:                              ; get and disable interrupt state
  1893.         add esp,26h                     ; adjust stack
  1894.         pop ds                          ; restore DS
  1895.  
  1896.         btc word ptr [esp+8],9          ; test and clear IF bit in EFLAGS
  1897.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1898.  
  1899.         jmp int31oknopop                ; return ok, dont pop registers
  1900.  
  1901. ;─────────────────────────────────────────────────────────────────────────────
  1902. int310901:                              ; get and enable interrupt state
  1903.         add esp,26h                     ; adjust stack
  1904.         pop ds                          ; restore DS
  1905.  
  1906.         bts word ptr [esp+8],9          ; test and set IF bit in EFLAGS
  1907.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1908.  
  1909.         jmp int31oknopop                ; return ok, dont pop registers
  1910.  
  1911. ;─────────────────────────────────────────────────────────────────────────────
  1912. int310902:                              ; get interrupt state
  1913.         add esp,26h                     ; adjust stack
  1914.         pop ds                          ; restore DS
  1915.  
  1916.         bt word ptr [esp+8],9           ; just test IF bit in EFLAGS
  1917.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1918.  
  1919.         jmp int31oknopop                ; return ok, dont pop registers
  1920.  
  1921. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1922. ; REAL/PROTECTED MODE TRANSLATION FUNCTIONS
  1923. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1924.  
  1925. ;─────────────────────────────────────────────────────────────────────────────
  1926. int310300:                              ; simulate real mode interrupt
  1927.         movzx ebx,bl                    ; get real mode INT CS:IP
  1928.         mov ebp,dword ptr ds:[ebx*4]
  1929.  
  1930.         jmp short int3103               ; go to common code
  1931.  
  1932. ;─────────────────────────────────────────────────────────────────────────────
  1933. int310301:                              ; call real mode FAR procedure
  1934.                                         ; same start as function 0302h
  1935. ;─────────────────────────────────────────────────────────────────────────────
  1936. int310302:                              ; call real mode IRET procedure
  1937.         mov ebp,dword ptr es:[edi+2ah]  ; get target CS:IP from structure
  1938.  
  1939. ;-----------------------------------------------------------------------------
  1940. int3103:                                ; common to 0300h, 0301h, and 0302h
  1941.         mov esi,cs:codebase             ; ESI = offset of PMODE_TEXT from 0
  1942.  
  1943.         movzx ebx,word ptr es:[edi+2eh] ; EBX = SP from register structure
  1944.         movzx edx,word ptr es:[edi+30h] ; EDX = SS from register structure
  1945.  
  1946.         mov ax,bx                       ; check if caller provided stack
  1947.         or ax,dx
  1948.         jnz short @@int3103f3           ; if yes, go on to set stack
  1949.  
  1950.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1951.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1952.         sub dx,bx                       ; adjust DX to next stack location
  1953.  
  1954.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1955.         jb int31fail8012                ; if yes, error 8012h
  1956.  
  1957.         mov ds:rmstacktop[esi],dx       ; update ptr for possible reenterancy
  1958.         shl bx,4                        ; adjust BX from paragraphs to bytes
  1959.  
  1960. @@int3103f3:
  1961.         lea edi,[edx*4]                 ; EDI -> top of real mode stack
  1962.         lea edi,[edi*4+ebx]
  1963.  
  1964.         lea ax,[bx-8]                   ; AX = top of stack parms
  1965.         xchg ax,ds:rmstackparmtop[esi]  ; preserve and set new top of stack
  1966.         push ax                         ;  parms for possible reenterancy
  1967.  
  1968.         movzx ax,byte ptr [esp+30]      ; AX = AL of original INT 31h call
  1969.         and al,1                        ; if function 0301h, AL=0, else, AL=2
  1970.         xor al,1
  1971.         shl al,1
  1972.         sub bx,ax                       ; adjust BX for possible FLAGS
  1973.  
  1974.         movzx eax,cx                    ; EAX = length of stack parms
  1975.         shl eax,1
  1976.         sub bx,36h                      ; adjust real mode SP for needed vars
  1977.         sub bx,ax                       ; adjust real mode SP for stack parms
  1978.  
  1979.         mov ds:[edi-2],ss               ; store SS:ESP on real mode stack
  1980.         mov ds:[edi-6],esp
  1981.         mov ds:[edi-8],es               ; store ES on real mode stack
  1982.  
  1983.         push ds                         ; swap DS and ES
  1984.         push es
  1985.         pop ds
  1986.         pop es
  1987.  
  1988.         std                             ; string copy backwards
  1989.  
  1990.         sub edi,10                      ; copy stack parms from protected mode
  1991.         movzx ecx,cx                    ;  stack to real mode stack
  1992.         lea esi,[esp+ecx*2+36h-2]
  1993.         rep movs word ptr es:[edi],word ptr ss:[esi]
  1994.  
  1995.         mov esi,[esp+2]                 ; ESI = offset of structure from stack
  1996.         mov ax,[esi+20h]                ; AX = FLAGS from register structure
  1997.  
  1998.         mov es:[edi],ax                 ; store data for real mode return IRET
  1999.  
  2000.         cmp byte ptr [esp+30],1         ; check AL on stack for function code
  2001.         je short @@int3103f4            ; if function 0301h, go on
  2002.  
  2003.         and ah,0fch                     ; 0300h or 0302h, clear IF and TF flag
  2004.  
  2005. @@int3103f4:
  2006.         cld                             ; string copy forward
  2007.         lea edi,[edx*4]                 ; EDI -> bottom of stack
  2008.         lea edi,[edi*4+ebx]
  2009.  
  2010.         mov ecx,8                       ; copy general regs to real mode stack
  2011.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  2012.  
  2013.         add esi,6                       ; copy FS and GS to real mode stack
  2014.         movs dword ptr es:[edi],dword ptr ds:[esi]
  2015.  
  2016.         mov word ptr es:[edi+8],PMODE_TEXT      ; return address from call
  2017.         mov word ptr es:[edi+6],off @@int3103f1
  2018.  
  2019.         mov es:[edi+4],ax               ; store FLAGS for real mode IRET maybe
  2020.         mov dword ptr es:[edi],ebp      ; put call address to real mode stack
  2021.  
  2022.         mov ax,[esi-6]                  ; real mode DS from register structure
  2023.         mov cx,[esi-8]                  ; real mode ES from register structure
  2024.  
  2025.         mov si,PMODE_TEXT               ; real mode target CS:IP
  2026.         mov di,off @@int3103f0
  2027.  
  2028.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  2029.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  2030.  
  2031. @@int3103f0:                            ; real mode INT, FAR, or IRET call
  2032.         popad                           ; load regs with call values
  2033.         pop fs gs
  2034.  
  2035.         iret                            ; go to call address
  2036.  
  2037. @@int3103f1:
  2038.         mov sp,cs:rmstackparmtop        ; remove stack parameters
  2039.  
  2040.         push gs fs ds es                ; store registers on stack
  2041.         pushf                           ; store flags on stack
  2042.         pushad
  2043.         cli
  2044.  
  2045.         mov ax,ss                       ; EAX = linear ptr to SS
  2046.         movzx eax,ax
  2047.         shl eax,4
  2048.         movzx ebp,sp                    ; EBP = SP
  2049.  
  2050.         mov cx,[bp+2ah]                 ; get protected mode ES from stack
  2051.         mov ebx,[bp+2ch]                ; get protected mode SS:ESP from stack
  2052.         mov dx,[bp+30h]
  2053.  
  2054.         add ebp,eax                     ; EBP -> stored regs on stack
  2055.  
  2056.         mov ax,SELZERO                  ; DS selector value for protected mode
  2057.         mov si,SELCODE                  ; target CS:EIP in protected mode
  2058.         mov edi,off @@int3103f2
  2059.  
  2060.         jmp cs:rmtopmswrout             ; go back to protected mode
  2061.  
  2062. @@int3103f2:
  2063.         mov edi,cs:codebase             ; restore old stack parameter length
  2064.         pop ds:rmstackparmtop[edi]
  2065.  
  2066.         mov edi,[esp]                   ; get structure offset from stack
  2067.         mov esi,ebp                     ; copy return regs from real mode
  2068.         mov ecx,15h                     ;  stack to register structure
  2069.         cld
  2070.         rep movs word ptr es:[edi],word ptr ds:[esi]
  2071.  
  2072.         cmp dword ptr es:[edi+4],0      ; stack provided by caller?
  2073.         jne int31ok                     ; if yes, done now
  2074.  
  2075.         mov edi,cs:codebase             ; restore top of real mode stack
  2076.         mov ax,cs:_pm_rmstacklen
  2077.         add ds:rmstacktop[edi],ax
  2078.  
  2079.         jmp int31ok                     ; return ok
  2080.  
  2081. ;─────────────────────────────────────────────────────────────────────────────
  2082. int310303:                              ; allocate real mode callback address
  2083.         mov bl,cs:_pm_callbacks         ; CL = total number of callbacks
  2084.         or bl,bl                        ; are there any?
  2085.         jz int31fail8015                ; if no, error 8015h
  2086.  
  2087.         mov edx,cs:callbackbase         ; EDX -> base of callbacks
  2088.         mov ecx,edx                     ; for later use
  2089.  
  2090. @@int310303l0:
  2091.         cmp word ptr [edx+3],0          ; is this callback free?
  2092.         jz short @@int310303f0          ; if yes, allocate
  2093.  
  2094.         add edx,25                      ; increment ptr to callback
  2095.         dec bl                          ; decrement loop counter
  2096.         jnz @@int310303l0               ; if more callbacks to check, loop
  2097.  
  2098.         jmp int31fail8015               ; no free callback, error 8015h
  2099.  
  2100. @@int310303f0:
  2101.         mov bx,[esp+38]                 ; BX = caller DS from stack
  2102.         mov [edx+3],bx                  ; store callback parms in callback
  2103.         mov [edx+7],esi
  2104.         mov [edx+12],es
  2105.         mov [edx+16],edi
  2106.  
  2107.         sub edx,ecx                     ; DX = offset of callback
  2108.         shr ecx,4                       ; CX = segment of callback
  2109.  
  2110.         jmp int31okdx                   ; return ok, with DX, CX, AX
  2111.  
  2112. ;─────────────────────────────────────────────────────────────────────────────
  2113. int310304:                              ; free real mode callback address
  2114.         cmp cx,cs:callbackseg           ; valid callback segment?
  2115.         jne int31fail8024               ; if no, error 8024h
  2116.  
  2117.         movzx ebx,dx                    ; EBX = offset of callback
  2118.  
  2119.         xor ax,ax                       ; check if valid offset
  2120.         xchg dx,ax
  2121.         mov cx,25
  2122.         div cx
  2123.  
  2124.         or dx,dx                        ; is there a remainder
  2125.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2126.  
  2127.         or ah,ah                        ; callback index too big?
  2128.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2129.  
  2130.         cmp al,cs:_pm_callbacks         ; callback index out of range?
  2131.         jae int31fail8024               ; if yes, not valid, error 8024h
  2132.  
  2133.         add ebx,cs:callbackbase         ; EBX -> callback
  2134.         mov word ptr [ebx+3],0          ; set callback as free
  2135.  
  2136.         jmp int31ok                     ; return ok
  2137.  
  2138. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2139. ; MISC FUNCTIONS
  2140. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2141.  
  2142. ;─────────────────────────────────────────────────────────────────────────────
  2143. int310305:                              ; get state save/restore addresses
  2144.         add esp,26h                     ; adjust stack
  2145.         pop ds                          ; restore DS
  2146.  
  2147.         xor ax,ax                       ; size needed is none
  2148.         mov bx,PMODE_TEXT               ; real mode seg of same RETF
  2149.         mov cx,off vxr_saverestorerm    ; same offset of 16bit RETF
  2150.         mov si,cs                       ; selector of routine is this one
  2151.         mov edi,off vxr_saverestorepm   ; offset of simple 32bit RETF
  2152.  
  2153.         jmp int31oknopop                ; return ok, dont pop registers
  2154.  
  2155. ;─────────────────────────────────────────────────────────────────────────────
  2156. int310306:                              ; get raw mode switch addresses
  2157.         add esp,26h                     ; adjust stack
  2158.         pop ds                          ; restore DS
  2159.  
  2160.         mov si,cs                       ; selector of pmtorm rout is this one
  2161.         mov edi,cs:pmtormswrout         ; offset in this seg of rout
  2162.         mov bx,PMODE_TEXT               ; real mode seg of rmtopm rout
  2163.         mov cx,cs:rmtopmswrout          ; offset of rout in real mode
  2164.  
  2165.         jmp int31oknopop                ; return ok, dont pop registers
  2166.  
  2167. ;─────────────────────────────────────────────────────────────────────────────
  2168. int310400:                              ; get version
  2169.         add esp,26h                     ; adjust stack
  2170.         pop ds                          ; restore DS
  2171.  
  2172.         mov ax,100h                     ; return version 1.0
  2173.         mov bx,3                        ; capabilities
  2174.         mov cl,cs:processortype         ; processor type
  2175.         mov dx,word ptr cs:picslave     ; master and slave PIC values
  2176.  
  2177.         jmp int31oknopop                ; return ok, dont pop registers
  2178.  
  2179. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2180. ; VCPI EXTENDED MEMORY FUNCTIONS
  2181. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2182.  
  2183. ;-----------------------------------------------------------------------------
  2184. int310500vsiditoesi:                    ; convert handle SI:DI to ptr ESI
  2185.         pop bp                          ; pop return address
  2186.  
  2187.         test di,3                       ; is handle (ptr) aligned on dword?
  2188.         jnz int31fail8023               ; if no, error 8023h
  2189.  
  2190.         shl esi,16                      ; ESI = SI:DI
  2191.         mov si,di
  2192.  
  2193.         cmp esi,cs:pagetablefree        ; handle too low?
  2194.         jb int31fail8023                ; if yes, error 8023h
  2195.  
  2196.         cmp esi,cs:pagetabletop         ; handle too high?
  2197.         jae int31fail8023               ; if yes, error 8023h
  2198.  
  2199.         test byte ptr [esi+1],2         ; is page first in allocated block?
  2200.         jz int31fail8023                ; if no, error 8023h
  2201.  
  2202.         jmp bp                          ; return ok
  2203.  
  2204. ;-----------------------------------------------------------------------------
  2205. int310500vbxcxtoebx:                    ; convert BX:CX bytes to EBX pages
  2206.         pop bp                          ; pop return address
  2207.  
  2208.         shl ebx,16                      ; EBX = BX:CX
  2209.         mov bx,cx
  2210.  
  2211.         or ebx,ebx                      ; check for invalid value
  2212.         jz int31fail8021                ; if invalid value, error 8021h
  2213.  
  2214.         add ebx,0fffh                   ; convert EBX to page count
  2215.         shr ebx,12
  2216.  
  2217.         jmp bp                          ; return ok
  2218.  
  2219. ;-----------------------------------------------------------------------------
  2220. int310500vpmalloc:                      ; allocate physical memory block
  2221.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2222.         xor ebp,ebp                     ; EBP = running allocated page count
  2223.  
  2224. @@int310500vpmallocl0:
  2225.         mov ax,0de04h                   ; VCPI allocate a page
  2226.         call fword ptr cs:vcpi_calleip
  2227.  
  2228.         or ah,ah                        ; got a page?
  2229.     jz short @@int310500vpmallocl0f0; if yes, go on
  2230.  
  2231.     cmp ebp,1            ; allocated any pages?
  2232.     jc short @@int310500vpmallocdone; if no, fail immediately
  2233.  
  2234.     or byte ptr [edi-3],4        ; set last allocated page as last
  2235.  
  2236.     call int310500vfree        ; free what was allocated
  2237.  
  2238.     stc                ; carry set, failed
  2239.     jmp short @@int310500vpmallocdone    ; go to done
  2240.  
  2241. @@int310500vpmallocl0f0:
  2242.         and dh,0f0h                     ; clear 4 bits of page table entry
  2243.         mov dl,7                        ; set page as user/writeable/present
  2244.         mov [edi],edx                   ; store page in page table
  2245.     add edi,4            ; increment page table ptr
  2246.  
  2247.     inc ebp             ; increment allocated page count
  2248.     cmp ebp,ebx            ; allocated all needed pages?
  2249.     jb @@int310500vpmallocl0    ; if no, loop
  2250.  
  2251.         or byte ptr [esi+1],2           ; set first allocated page as first
  2252.         or byte ptr [edi-3],4           ; set last allocated page as last
  2253.         clc                             ; carry clear, success
  2254.  
  2255. @@int310500vpmallocdone:
  2256.         mov eax,ebp                     ; EAX = number of pages allocated
  2257.     ret                ; return
  2258.  
  2259. ;-----------------------------------------------------------------------------
  2260. int310500vlmalloc:                      ; check for linear memory block
  2261.         mov edi,cs:pagetablefree        ; EDI = search ptr in page table
  2262.  
  2263.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2264.         sub ecx,edi
  2265.         shr ecx,2
  2266.  
  2267.         xor edx,edx                     ; EDX = largest linear block found
  2268.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2269.  
  2270.         push ebx                        ; preserve EBX, memory requested
  2271.  
  2272. @@int310500vlmallocl0:
  2273.         jecxz short @@int310500vlmallocdone     ; if no more entries, done
  2274.  
  2275.         repne scas dword ptr es:[edi]   ; search for first next free entry
  2276.         jne short @@int310500vlmallocdone       ; if no more free, go on
  2277.  
  2278.         mov ebp,ecx                     ; EBP = current count
  2279.         lea ebx,[edi-4]                 ; EBX = start of free block
  2280.  
  2281.         repe scas dword ptr es:[edi]    ; search for end of free linear block
  2282.         jne short @@int310500vlmallocl0f0; if previous entry not free, go on
  2283.  
  2284.         inc ebp                         ; previous entry free, extra one
  2285.  
  2286. @@int310500vlmallocl0f0:
  2287.         sub ebp,ecx                     ; EBP = number of free pages in block
  2288.  
  2289.         cmp ebp,edx                     ; new block larger than last largest?
  2290.         jb @@int310500vlmallocl0        ; if no, loop
  2291.  
  2292.         mov esi,ebx                     ; ESI = ptr to largest block found
  2293.         mov edx,ebp                     ; size of new largest block found
  2294.  
  2295.         cmp ebp,[esp]                   ; block sufficient for memory request?
  2296.         jb @@int310500vlmallocl0        ; if no, loop
  2297.  
  2298. @@int310500vlmallocdone:
  2299.         pop ebx                         ; restore EBX, memory requested
  2300.         ret                             ; return
  2301.  
  2302. ;-----------------------------------------------------------------------------
  2303. int310500vmalloc:                       ; allocate linear+physical mem block
  2304.         call int310500vlmalloc          ; try to allocate linear memory block
  2305.  
  2306.         cmp edx,1                       ; found ANY free linear area?
  2307.         jc short @@int310500vmallocdone ; if no, done
  2308.  
  2309.         cmp edx,ebx                     ; linear block enough for request?
  2310.         jb short @@int310500vmallocf0   ; if no, go to physical memory check
  2311.  
  2312.         call int310500vpmalloc          ; try to allocate physical mem
  2313.  
  2314.         mov cl,1                        ; error is not enough physical memory
  2315.         jmp short @@int310500vmallocdone; go to done
  2316.  
  2317. @@int310500vmallocf0:
  2318.         mov ebx,edx                     ; only linear block size physical mem
  2319.  
  2320.         call int310500vpmalloc          ; try to allocate physical memory
  2321.         jc short @@int310500vmallocfaillinear   ; if failed, done
  2322.  
  2323.         call int310500vfree             ; success, so must free block
  2324.  
  2325.         mov eax,ebx                     ; can allocate this much total memory
  2326.         stc                             ; carry set, failed
  2327.  
  2328. @@int310500vmallocfaillinear:
  2329.         mov cl,0                        ; error is not enough linear memory
  2330.  
  2331. @@int310500vmallocdone:
  2332.         ret                             ; return
  2333.  
  2334. ;-----------------------------------------------------------------------------
  2335. int310500vfree:                         ; free linear+physical memory block
  2336.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2337.  
  2338. @@int310500vfreel0:
  2339.         xor ecx,ecx                     ; new page table entry is free (0)
  2340.     xchg ecx,[edi]            ; swap ECX with page table entry
  2341.     add edi,4            ; increment page table ptr
  2342.  
  2343.         mov edx,ecx                     ; EDX = page table entry
  2344.         and dx,0f000h                   ; mask off low 12 bits
  2345.  
  2346.         mov ax,0de05h                   ; VCPI free a page
  2347.         call fword ptr cs:vcpi_calleip
  2348.  
  2349.         test ch,4                       ; last page of block?
  2350.         jz @@int310500vfreel0           ; if no, loop
  2351.  
  2352.         ret                             ; return
  2353.  
  2354. ;─────────────────────────────────────────────────────────────────────────────
  2355. int310500v:                             ; VCPI get free memory information
  2356.         push ds                         ; ES = DS for VCPI malloc functions
  2357.         pop es
  2358.  
  2359.         mov ebx,0ffffffffh              ; try to allocate an impossible amount
  2360.         call int310500vmalloc
  2361.  
  2362.         shl eax,12                      ; returned EAX is highest possible
  2363.  
  2364.         jmp int310500xsetbuf            ; put memory information in buffer
  2365.  
  2366. ;─────────────────────────────────────────────────────────────────────────────
  2367. int310501v:                             ; VCPI allocate memory block
  2368.         push ds                         ; ES = DS for VCPI malloc functions
  2369.         pop es
  2370.  
  2371.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2372.  
  2373.         call int310500vmalloc           ; try to allocate requested amount
  2374.         jnc short int310501vaddxnhandle ; if successful, go to done
  2375.  
  2376.         or cl,cl                        ; error is not enough linear memory?
  2377.         jz int31fail8012                ; if yes, error 8013h
  2378.         jmp int31fail8013               ; error is physical, error 8013h
  2379.  
  2380. int310501vaddxnhandle:
  2381.         mov ecx,esi                     ; figure address of block from handle
  2382.         sub ecx,cs:pagetablebase
  2383.         shl ecx,10
  2384.         shld ebx,ecx,16
  2385.  
  2386.         mov di,si                       ; SI:DI = ESI, handle
  2387.         shr esi,16
  2388.  
  2389.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2390.         mov cr3,eax
  2391.  
  2392.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2393.  
  2394. ;─────────────────────────────────────────────────────────────────────────────
  2395. int310502v:                             ; VCPI free memory block
  2396.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2397.  
  2398.         call int310500vfree             ; free memory block
  2399.  
  2400.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2401.         mov cr3,eax
  2402.  
  2403.         jmp int31ok                     ; return ok
  2404.  
  2405. ;─────────────────────────────────────────────────────────────────────────────
  2406. int310503v:                             ; VCPI resize memory block
  2407.         push ds                         ; ES = DS for VCPI malloc functions
  2408.         pop es
  2409.  
  2410.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2411.  
  2412.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2413.  
  2414.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2415.         xor ebp,ebp                     ; EBP = running block size in pages
  2416.  
  2417. @@int310503vl0:
  2418.         add edi,4                       ; increment page table ptr
  2419.         inc ebp                         ; increment block size
  2420.  
  2421.         test byte ptr [edi-3],4         ; last page of block?
  2422.         jz @@int310503vl0               ; if no, loop
  2423.  
  2424.         sub ebx,ebp                     ; EBX = change in block size
  2425.         jz int310501vaddxnhandle        ; if no change, done
  2426.  
  2427.         jc @@int310503vf0               ; if block made smaller, just free top
  2428.  
  2429.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2430.         sub ecx,edi
  2431.         shr ecx,2
  2432.  
  2433.         mov edx,ecx                     ; EDX = current count
  2434.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2435.  
  2436.         jecxz short @@int310503vf3      ; if no entries above, try below
  2437.  
  2438.         repe scas dword ptr es:[edi]    ; check for free entries above block
  2439.         je short @@int310503vf2         ; if previous entry free, go on
  2440.  
  2441.         dec edx                         ; previous entry not free, minus one
  2442.  
  2443. @@int310503vf2:
  2444.         sub edx,ecx                     ; EDX = number of free pages in block
  2445.  
  2446.         cmp edx,ebx                     ; enough linear memory?
  2447.         jb short @@int310503vf3         ; if no, try below in linear memory
  2448.  
  2449.         push esi                        ; preserve start of block
  2450.         lea esi,[esi+ebp*4]             ; ESI -> start of new block for alloc
  2451.  
  2452.         call int310500vpmalloc          ; try to allocate physical memory
  2453.         mov edi,esi                     ; EDI -> start of new block
  2454.         pop esi                         ; restore start of old block
  2455.         jc int31fail8013                ; if alloc failed, error 8013h
  2456.  
  2457.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2458.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2459.  
  2460.         jmp int310501vaddxnhandle       ; go to done
  2461.  
  2462. @@int310503vf3:
  2463.         mov ecx,esi                     ; ECX = count of pages to search up
  2464.         sub ecx,cs:pagetablefree
  2465.         shr ecx,2
  2466.  
  2467.         or ecx,ecx                      ; any linear memory below?
  2468.         jz @@int310503vf1               ; if no, try to allocate
  2469.  
  2470.         push ebp                        ; preserve size of original block
  2471.  
  2472.         lea edi,[esi-4]                 ; EDI = ESI, ptr to linear block start
  2473.         mov ebp,ecx                     ; EBP = current count
  2474.  
  2475.         std                             ; search is up
  2476.         repe scas dword ptr es:[edi]    ; check for free entries after block
  2477.         cld
  2478.         je short @@int310503vf4         ; if previous entry free, go on
  2479.  
  2480.         dec ebp                         ; previous entry not free, minus one
  2481.  
  2482. @@int310503vf4:
  2483.         sub ebp,ecx                     ; EBP = number of free pages in block
  2484.         lea eax,[ebp+edx]               ; free size below + free size above
  2485.  
  2486.         pop ebp                         ; restore original block size
  2487.  
  2488.         cmp eax,ebx                     ; enough linear memory?
  2489.         jb @@int310503vf1               ; if no, try to allocate
  2490.  
  2491.         push esi                        ; preserve original block address
  2492.  
  2493.         sub ebx,edx                     ; EBX = number of pages needed below
  2494.         lea eax,[ebx*4]                 ; get base of block below
  2495.         sub esi,eax
  2496.  
  2497.         push edx ebp                    ; preserve some vars
  2498.         call int310500vpmalloc          ; try to allocate physical memory
  2499.         pop ebp edx                     ; restore some vars
  2500.  
  2501.         mov edi,esi                     ; EDI -> base of block below
  2502.         pop esi                         ; restore base of original block
  2503.         jc int31fail8013                ; if alloc failed, error 8013h
  2504.  
  2505.         or edx,edx                      ; any pages needed above?
  2506.         jz short @@int310503vf6         ; if no, go on
  2507.  
  2508.         push esi edi ebp                ; preserve some vars
  2509.  
  2510.         mov ebx,edx                     ; EBX = size of block below
  2511.         lea esi,[esi+ebp*4]             ; ESI -> start of block above
  2512.  
  2513.         call int310500vpmalloc          ; try to allocate physical memory
  2514.         pop ebp edi esi                 ; restore some vars
  2515.         jnc short @@int310503vf5        ; if allocated ok, go on
  2516.  
  2517.         mov esi,edi                     ; ESI -> allocated block below
  2518.         call int310500vfree             ; free allocated block below
  2519.  
  2520.         jmp int31fail8013               ; fail, error 8013h
  2521.  
  2522. @@int310503vf5:
  2523.         and byte ptr [esi-3],0fbh       ; clear last bit in below block end
  2524.         and byte ptr [esi+ebp*4+1],0fdh ; clear first bit in above block start
  2525.  
  2526. @@int310503vf6:
  2527.         and byte ptr [edi+1],0fdh       ; clear first bit in below block start
  2528.         and byte ptr [esi+ebp*4-3],0fbh ; clear last bit in old block end
  2529.  
  2530.         push edi                        ; preserve new block start
  2531.  
  2532.         mov edx,edi                     ; EDX = base of move area
  2533.         lea ebx,[esi-4]                 ; EBX = current location in move area
  2534.  
  2535. @@int310503vl1:
  2536.         mov edi,ebx                     ; set up to shift up a page
  2537.         mov esi,ebx
  2538.         mov ecx,ebp
  2539.  
  2540.         lods dword ptr ds:[esi]         ; shift old pages a page down in table
  2541.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  2542.         stos dword ptr es:[edi]
  2543.  
  2544.         sub ebx,4                       ; decrement to next page to shift
  2545.         cmp ebx,edx                     ; more pages to shift?
  2546.         jae @@int310503vl1              ; if yes, loop
  2547.  
  2548.         pop esi                         ; restore new block start address
  2549.  
  2550.         jmp int310501vaddxnhandle       ; go to done
  2551.  
  2552. @@int310503vf1:
  2553.         add ebx,ebp                     ; restore EBX as requested size
  2554.  
  2555.         push esi ebp                    ; preserve some vars
  2556.         call int310500vlmalloc          ; check for linear memory block
  2557.         pop ebp edi                     ; restore some vars
  2558.  
  2559.         cmp edx,ebx                     ; enough linear memory?
  2560.         jb int31fail8012                ; if no, error 8012h
  2561.  
  2562.         sub ebx,ebp                     ; EBX = extra pages needed
  2563.         push esi                        ; preserve for later copy
  2564.         lea esi,[esi+ebp*4]             ; ESI -> start of extra space needed
  2565.  
  2566.         push edi ebp                    ; preserve some vars
  2567.         call int310500vpmalloc          ; try to allocate physical memory
  2568.         pop ecx esi edi                 ; restore some vars
  2569.         jc int31fail8013                ; if not enough mem, error 8013h
  2570.  
  2571.         push edi esi ecx                ; preserve, new and old block, size
  2572.  
  2573.         rep movs dword ptr es:[edi],dword ptr ds:[esi]  ; copy old block pages
  2574.  
  2575.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2576.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2577.  
  2578.         pop ecx edi                     ; restore to clear old block
  2579.  
  2580.         xor eax,eax                     ; new page table entry is free (0)
  2581.         rep stos dword ptr es:[edi]     ; clear old page table block
  2582.  
  2583.         pop esi                         ; restore new block address
  2584.  
  2585.         jmp int310501vaddxnhandle       ; go to done
  2586.  
  2587. @@int310503vf0:
  2588.         sub edi,4                       ; decrement page table ptr
  2589.  
  2590.         xor edx,edx                     ; new page table entry is free (0)
  2591.         xchg edx,[edi]                  ; swap EDX with page table entry
  2592.         and dx,0f000h                   ; mask off low 12 bits
  2593.  
  2594.         mov ax,0de05h                   ; VCPI free a page
  2595.         call fword ptr cs:vcpi_calleip
  2596.  
  2597.         inc ebx                         ; increment negative change counter
  2598.         jnz @@int310503vf0              ; if more pages to free, loop
  2599.  
  2600.         or byte ptr [edi-3],4           ; set next page up as last of block
  2601.  
  2602.         jmp int310501vaddxnhandle       ; go to done
  2603.  
  2604. ;─────────────────────────────────────────────────────────────────────────────
  2605. int31050av:                             ; VCPI get memory block size and base
  2606.         shrd ecx,esi,16                 ; figure address of block from handle
  2607.         mov cx,di
  2608.         sub ecx,cs:pagetablebase
  2609.         shl ecx,10
  2610.         shld ebx,ecx,16
  2611.  
  2612.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2613.  
  2614.         xor edi,edi                     ; EDI = running page count
  2615.  
  2616. @@int31050avl0:
  2617.         inc edi                         ; increment page count
  2618.  
  2619.         lods dword ptr ds:[esi]         ; EAX = page table entry
  2620.         test ah,4                       ; is this the last page of the block?
  2621.         jz @@int31050avl0               ; if no, loop
  2622.  
  2623.         shl edi,12                      ; convert EDI pages to bytes
  2624.         shld esi,edi,16                 ; SI:DI = EDI, size in bytes
  2625.  
  2626.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2627.  
  2628. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2629. ; XMS EXTENDED MEMORY FUNCTIONS
  2630. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2631.  
  2632. ;-----------------------------------------------------------------------------
  2633. int310500xsetbuf:
  2634.         mov es,[esp+24h]                ; get ES:EDI buffer ptr from stack
  2635.         mov edi,[esp]
  2636.  
  2637.         stos dword ptr es:[edi]         ; store block size in output buffer
  2638.         mov ecx,0bh                     ; fill rest of buffer with 0ffffffffh
  2639.         mov eax,0ffffffffh
  2640.         rep stos dword ptr es:[edi]
  2641.  
  2642.         jmp int31ok                     ; return ok
  2643.  
  2644. ;-----------------------------------------------------------------------------
  2645. int310500xcallxms:                      ; make a all to real mode XMS driver
  2646.         pop bp                          ; pop return address
  2647.         sub esp,32h                     ; stack space for register structure
  2648.  
  2649.         mov [esp+1ch],ax                ; put AX in register structure
  2650.         mov [esp+10h],bx                ; put BX in register structure
  2651.         mov [esp+18h],cx                ; put CX in register structure
  2652.         mov [esp+14h],dx                ; put DX in register structure
  2653.  
  2654.         mov word ptr [esp+20h],0        ; zero FLAGS in register structure
  2655.         mov dword ptr [esp+2eh],0       ; zero SS:SP in register structure
  2656.         mov eax,dword ptr cs:xms_callip ; put XMS driver address in CS:IP in
  2657.         mov [esp+2ah],eax               ;  regis]er structure
  2658.  
  2659.         push ss                         ; ES:EDI -> register structure
  2660.         pop es
  2661.         mov edi,esp
  2662.  
  2663.         xor cx,cx                       ; copy 0 words as stack parameters
  2664.         xor bh,bh                       ; doesnt really need to be here
  2665.         mov ax,301h                     ; call real mode FAR procedure
  2666.         int 31h
  2667.  
  2668.         mov ax,[esp+1ch]                ; get AX from register structure
  2669.         mov bx,[esp+10h]                ; get BX from register structure
  2670.         mov cx,[esp+18h]                ; get CX from register structure
  2671.         mov dx,[esp+14h]                ; get DX from register structure
  2672.  
  2673.         lea esp,[esp+32h]               ; adjust ESP without changing FLAGS
  2674.         jc int31fail8010                ; if INT 31h failed, error 8010h
  2675.  
  2676.         jmp bp                          ; return ok
  2677.  
  2678. ;-----------------------------------------------------------------------------
  2679. int310500xbxcxtodx:                     ; convert BX:CX bytes to DX K
  2680.         pop bp                          ; pop return address
  2681.  
  2682.         mov dx,cx                       ; check for invalid value, BX=CX=0
  2683.         or dx,bx
  2684.         jz int31fail8021                ; if invalid value, error 8021h
  2685.  
  2686.         add cx,1023+15                  ; adjust for size in K and align
  2687.         adc bx,0
  2688.  
  2689.         test bh,0fch                    ; memory request too high
  2690.         jnz int31fail8013               ; if yes, error 8013h
  2691.  
  2692.         shrd cx,bx,10                   ; CX = memory in K
  2693.         mov dx,cx
  2694.  
  2695.         jmp bp                          ; return ok
  2696.  
  2697. ;-----------------------------------------------------------------------------
  2698. int310500xerror:                        ; XMS error, return with DPMI error
  2699.         cmp bl,0a0h                     ; out of memory?
  2700.         je int31fail8013                ; if yes, error 8013h
  2701.  
  2702.         cmp bl,0a1h                     ; handles exhausted?
  2703.         je int31fail8016                ; if yes, error 8016h
  2704.  
  2705.         cmp bl,0a2h                     ; invalid handle?
  2706.         je int31fail8023                ; if yes, error 8023h
  2707.  
  2708.         jmp int31fail8010               ; else, error 8010h
  2709.  
  2710. ;─────────────────────────────────────────────────────────────────────────────
  2711. int310500x:                             ; XMS get free memory information
  2712.         mov ah,8                        ; get largest free memory block in K
  2713.         call int310500xcallxms
  2714.  
  2715.         movzx eax,ax                    ; EAX = free memory in bytes
  2716.         shl eax,10
  2717.  
  2718.         sub eax,15                      ; adjust by extra alignment size
  2719.         jnc int310500xsetbuf            ; if no overflow, put info to buffer
  2720.  
  2721.         xor eax,eax                     ; overflow, so no memory available
  2722.         jmp int310500xsetbuf            ; put memory information in buffer
  2723.  
  2724. ;─────────────────────────────────────────────────────────────────────────────
  2725. int310501x:                             ; XMS allocate memory block
  2726.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2727.         mov cx,dx                       ; preserve size of block in K
  2728.  
  2729.         mov ah,9                        ; allocate DX K of XMS memory
  2730.         call int310500xcallxms
  2731.         or ax,ax                        ; error?
  2732.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2733.  
  2734.         mov si,dx                       ; get DPMI handle from XMS handle
  2735.  
  2736. int310501xgotmem:
  2737.         mov ah,0ch                      ; lock memory block
  2738.         call int310500xcallxms
  2739.         or ax,ax                        ; error?
  2740.         jnz short @@int310501xf0        ; if no, go on
  2741.  
  2742.         push bx                         ; yup, preserve error number
  2743.  
  2744.         mov ah,0ah                      ; free block causing lock error
  2745.         call int310500xcallxms
  2746.  
  2747.         pop bx                          ; restore error number
  2748.         jmp int310500xerror             ; XMS error, return with DPMI error
  2749.  
  2750. @@int310501xf0:
  2751.         mov di,cx                       ; low word of DPMI handle is size in K
  2752.  
  2753.         mov cx,bx                       ; XMS linear address to DPMI regs
  2754.         mov bx,dx
  2755.  
  2756.         add cx,0fh                      ; align linear address on paragraph
  2757.         adc bx,0
  2758.         and cl,0f0h
  2759.  
  2760.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2761.  
  2762. ;─────────────────────────────────────────────────────────────────────────────
  2763. int310502x:                             ; XMS free memory block
  2764.         mov dx,si                       ; get XMS handle from DPMI handle
  2765.  
  2766.         mov ah,0dh                      ; unlock memory block
  2767.         call int310500xcallxms
  2768.         or ax,ax                        ; error?
  2769.         jz int310500xerror              ; if XMS error, return with DPMI error
  2770.  
  2771.         mov ah,0ah                      ; free memory block
  2772.         call int310500xcallxms
  2773.         or ax,ax                        ; error?
  2774.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2775.  
  2776.         jmp int31ok                     ; return ok
  2777.  
  2778. ;─────────────────────────────────────────────────────────────────────────────
  2779. int310503x:                             ; XMS resize memory block
  2780.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2781.         mov cx,dx                       ; preserve size of block in K
  2782.         mov dx,si                       ; get XMS handle from DPMI handle
  2783.  
  2784.         mov ah,0dh                      ; unlock memory block
  2785.         call int310500xcallxms
  2786.         or ax,ax                        ; error?
  2787.         jz int310500xerror              ; if XMS error, return with DPMI error
  2788.  
  2789.         mov bx,cx                       ; BX = new size in K
  2790.         mov ah,0fh                      ; resize memory block
  2791.         call int310500xcallxms
  2792.         mov dx,si                       ; get XMS handle again
  2793.         or ax,ax                        ; error in resize?
  2794.         jnz int310501xgotmem            ; if no, go to memory block code
  2795.  
  2796.         push bx                         ; yup, preserve error number
  2797.  
  2798.         mov ah,0ch                      ; lock memory block
  2799.         call int310500xcallxms
  2800.  
  2801.         pop bx                          ; restore error number
  2802.         jmp int310500xerror             ; XMS error, return with DPMI error
  2803.  
  2804. ;─────────────────────────────────────────────────────────────────────────────
  2805. int31050ax:                             ; XMS get memory block size and base
  2806.         mov dx,si                       ; get XMS handle from DPMI handle
  2807.         mov si,di                       ; SI = size of block in K
  2808.  
  2809.         mov ah,0dh                      ; unlock memory block
  2810.         call int310500xcallxms
  2811.         or ax,ax                        ; error?
  2812.         jz int310500xerror              ; if XMS error, return with DPMI error
  2813.  
  2814.         mov ah,0ch                      ; lock memory block
  2815.         call int310500xcallxms
  2816.         or ax,ax                        ; error?
  2817.         jz int310500xerror              ; if XMS error, return with DPMI error
  2818.  
  2819.         xor di,di                       ; convert size in K to size in bytes
  2820.         shrd di,si,6
  2821.         shr si,6
  2822.  
  2823.         mov cx,bx                       ; XMS linear address to DPMI regs
  2824.         mov bx,dx
  2825.  
  2826.         mov ax,cx                       ; figure out alignment stub
  2827.         dec ax
  2828.         and ax,0fh
  2829.         xor al,0fh
  2830.  
  2831.         sub di,ax                       ; subtract alignment stub from size
  2832.         sbb si,0
  2833.  
  2834.         add cx,0fh                      ; align linear address on paragraph
  2835.         adc bx,0
  2836.         and cl,0f0h
  2837.  
  2838.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2839.  
  2840. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2841. ; RAW EXTENDED MEMORY FUNCTIONS
  2842. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2843.  
  2844. ;-----------------------------------------------------------------------------
  2845. int310500rnomem:                        ; no free extended memory present
  2846.         xor eax,eax                     ; 0 available extended memory
  2847.         jmp int310500xsetbuf            ; put memory information in buffer
  2848.  
  2849. ;-----------------------------------------------------------------------------
  2850. int310500rbxcxtoebx:                    ; convert BX:CX bytes to EBX bytes
  2851.         pop bp                          ; pop return address
  2852.  
  2853.         shl ebx,16                      ; EBX = BX:CX
  2854.         mov bx,cx
  2855.  
  2856.         or ebx,ebx                      ; check for invalid value
  2857.         jz int31fail8021                ; if invalid value, error 8021h
  2858.  
  2859.         add ebx,0fh                     ; align EBX on paragraph
  2860.         and bl,0f0h
  2861.  
  2862.         jmp bp                          ; return ok
  2863.  
  2864. ;-----------------------------------------------------------------------------
  2865. int310500rfindmcb:                      ; find MCB for handle SI:DI
  2866.         pop bp                          ; pop return address
  2867.  
  2868.         shl esi,16                      ; ESI = handle SI:DI = address of MCB
  2869.         mov si,di
  2870.  
  2871.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2872.  
  2873. @@int310500rfindmcbl0:
  2874.         cmp edi,esi                     ; found MCB?
  2875.         jne short @@int310500rfindmcbl0f0       ; if no, keep looking
  2876.  
  2877.         cmp byte ptr [edi-4],0          ; memory block free?
  2878.         je int31fail8023                ; if yes, error 8023h
  2879.  
  2880.         jmp bp                          ; return ok, found MCB
  2881.  
  2882. @@int310500rfindmcbl0f0:
  2883.         mov edi,[edi-12]                ; EDI -> next memory control block
  2884.         or edi,edi                      ; is there another MCB?
  2885.         jnz @@int310500rfindmcbl0       ; if yes, loop
  2886.  
  2887.         jmp int31fail8023               ; fail, error 8023h
  2888.  
  2889. ;-----------------------------------------------------------------------------
  2890. int310500radjustused:                   ; adjust INT 15h extended memory used
  2891.         mov eax,cs:rawextmemtop         ; EAX -> first memory control block
  2892.  
  2893. @@int310500radjustusedl0:
  2894.         cmp dword ptr [eax-12],0        ; last memory control block?
  2895.         jz short @@int310500radjustusedf0       ; if yes, go to set new used K
  2896.  
  2897.         mov eax,[eax-12]                ; EAX -> next memory control block
  2898.         jmp @@int310500radjustusedl0    ; loop
  2899.  
  2900. @@int310500radjustusedf0:
  2901.         cmp byte ptr [eax-4],0          ; memory block free?
  2902.         je short @@int310500radjustusedf1       ; if no, go on
  2903.  
  2904.         sub eax,[eax-16]                ; used, adjust by size of block
  2905.  
  2906. @@int310500radjustusedf1:
  2907.         sub eax,10h                     ; adjust by size of MCB
  2908.         and eax,0fffffc00h              ; align on K
  2909.         sub eax,cs:rawextmemtop         ; size of extended memory used
  2910.         neg eax
  2911.         shr eax,10                      ; convert from bytes to K
  2912.  
  2913.         mov ebp,cs:codebase             ; EBP = offset of PMODE_TEXT from 0
  2914.         mov ds:rawextmemused[ebp],ax    ; adjust INT 15h extended memory used
  2915.  
  2916. @@int310500radjustuseddone:
  2917.         ret                             ; return
  2918.  
  2919. ;-----------------------------------------------------------------------------
  2920. int310500rlinkmcb:                      ; link memory blocks at ESI and EDI
  2921.         mov eax,[esi-16]                ; combine two block sizes
  2922.         add eax,10h
  2923.         add [edi-16],eax                ; add size of next block to this one
  2924.         mov ecx,[esi-12]                ; copy next MCB field
  2925.         mov [edi-12],ecx
  2926.         jecxz short @@int310500rlinkmcbf0       ; if no next MCB, done
  2927.  
  2928.         mov [ecx-8],edi                 ; set prev MCB in next MCB to this MCB
  2929.  
  2930. @@int310500rlinkmcbf0:
  2931.         ret                             ; return
  2932.  
  2933. ;─────────────────────────────────────────────────────────────────────────────
  2934. int310500r:                             ; raw get free memory information
  2935.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2936.  
  2937.         xor eax,eax                     ; running highest free memory block
  2938. @@int310500rl0:
  2939.         cmp byte ptr [edi-4],0          ; is block free?
  2940.         jne short @@int310500rl0f0      ; if no, loop
  2941.  
  2942.         mov ebx,[edi-16]                ; EBX = size of block
  2943.         cmp eax,ebx                     ; last free block larger?
  2944.         ja short @@int310500rl0f0       ; if yes, loop
  2945.  
  2946.         mov eax,ebx                     ; found larger block, new largest
  2947.  
  2948. @@int310500rl0f0:
  2949.         mov edi,[edi-12]                ; EDI -> next memory control block
  2950.         or edi,edi                      ; is there another MCB?
  2951.         jnz @@int310500rl0              ; if yes, loop
  2952.  
  2953.         jmp int310500xsetbuf            ; put memory information in buffer
  2954.  
  2955. ;─────────────────────────────────────────────────────────────────────────────
  2956. int310501r:                             ; raw allocate memory block
  2957.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  2958.  
  2959.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2960.  
  2961. @@int310501rl0:
  2962.         cmp byte ptr ds:[edi-4],0       ; is block free?
  2963.         je short @@int310501rl0f2       ; if yes, check block
  2964.  
  2965. @@int310501rl0f0:
  2966.         mov edi,[edi-12]                ; EDI -> next memory control block
  2967.         or edi,edi                      ; is there another MCB?
  2968.         jnz @@int310501rl0              ; if yes, loop
  2969.  
  2970.         jmp int31fail8013               ; fail, error 8013h
  2971.  
  2972. @@int310501rl0f2:
  2973.         lea ecx,[edi-10h]               ; ECX -> possible new MCB
  2974.         sub ecx,ebx
  2975.  
  2976.         mov eax,[edi-16]                ; EAX = size of block
  2977.         sub eax,ebx                     ; enough free memory in block?
  2978.         jc short @@int310501rl0f0       ; if no, loop
  2979.  
  2980.         jz short @@int310501rl0f1       ; if exactly same size, continue
  2981.  
  2982.         sub eax,10h                     ; adjust for size of new created MCB
  2983.         mov [ecx-16],eax                ; put size of new block in new MCB
  2984.         mov eax,ecx                     ; set next MCB in old MCB as new one
  2985.         xchg [edi-12],eax               ; copy next MCB from old to new MCB
  2986.         mov [ecx-12],eax
  2987.         or eax,eax                      ; is there a next MCB?
  2988.         jz short @@int310501rl0f3       ; if no, go on
  2989.  
  2990.         mov [eax-8],ecx                 ; set prev MCB in next MCB to new MCB
  2991.  
  2992. @@int310501rl0f3:
  2993.         mov [ecx-8],edi                 ; set prev MCB in new MCB as old one
  2994.         mov byte ptr [ecx-4],0          ; set new MCB as free
  2995.         mov [edi-16],ebx                ; set size of allocated block
  2996.  
  2997. @@int310501rl0f1:
  2998.         mov byte ptr [edi-4],1          ; set block as allocated
  2999.  
  3000. int310501raddxnhandle:
  3001.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  3002.         shld esi,edi,16                 ; SI:DI = EDI, handle (address of MCB)
  3003.  
  3004.         call int310500radjustused       ; adjust INT 15h extended memory used
  3005.  
  3006.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  3007.  
  3008. ;─────────────────────────────────────────────────────────────────────────────
  3009. int310502r:                             ; raw free memory block
  3010.         call int310500rfindmcb          ; find MCB for handle SI:DI
  3011.  
  3012.         mov byte ptr [edi-4],0          ; set this memory block as free
  3013.  
  3014.         mov esi,[edi-12]                ; ESI -> next memory control block
  3015.         or esi,esi                      ; is there next MCB?
  3016.         jz short @@int310502rf0         ; if no, go on
  3017.  
  3018.         cmp byte ptr [esi-4],0          ; is next memory block free?
  3019.         jne short @@int310502rf0        ; if no, go on
  3020.  
  3021.         call int310500rlinkmcb          ; link two memory blocks
  3022.  
  3023. @@int310502rf0:
  3024.         mov esi,[edi-8]                 ; ESI -> previous memory control block
  3025.         or esi,esi                      ; is there previous MCB?
  3026.         jz short @@int310502rf1         ; if no, go on
  3027.  
  3028.         cmp byte ptr [esi-4],0          ; is previous memory block free?
  3029.         jne short @@int310502rf1        ; if no, go on
  3030.  
  3031.         xchg esi,edi                    ; change mcb order for function
  3032.         call int310500rlinkmcb          ; link two memory blocks
  3033.  
  3034. @@int310502rf1:
  3035.         call int310500radjustused       ; adjust INT 15h extended memory used
  3036.  
  3037.         jmp int31ok                     ; return ok
  3038.  
  3039. ;─────────────────────────────────────────────────────────────────────────────
  3040. int310503r:                             ; raw resize memory block
  3041.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  3042.         mov edx,ebx                     ; EDX = size of new block
  3043.  
  3044.         call int310500rfindmcb          ; find MCB for handle SI:DI
  3045.  
  3046.         push ds                         ; ES = DS for possible block copy
  3047.         pop es
  3048.  
  3049.         sub ebx,[esi-16]                ; EBX = change in block size
  3050.         jz @@int310503rf0               ; if no change, done
  3051.  
  3052.         jc @@int310503rf1               ; if block made smaller, just free top
  3053.  
  3054.         xor eax,eax                     ; running memory counter
  3055.  
  3056.         mov ecx,[esi-12]                ; ECX -> next MCB
  3057.         jecxz short @@int310503rf4      ; if no next MCB, check previous MCB
  3058.  
  3059.         cmp byte ptr [ecx-4],0          ; next MCB free?
  3060.         jne short @@int310503rf4        ; if not, check previous MCB
  3061.  
  3062.         mov eax,[ecx-16]                ; EAX = amount of free memory in block
  3063.         add eax,10h                     ;  including memory control block
  3064.  
  3065. @@int310503rf4:
  3066.         mov ecx,[esi-8]                 ; ECX -> previous MCB
  3067.         jecxz short @@int310503rf5      ; if no previous MCB, check memory
  3068.  
  3069.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3070.         jne short @@int310503rf5        ; if not, check memory
  3071.  
  3072.         add eax,[ecx-16]                ; add amount of free memory in block
  3073.         add eax,10h                     ;  including memory control block
  3074.  
  3075. @@int310503rf5:
  3076.         cmp eax,ebx                     ; enough to resize within area
  3077.         jb @@int310503rf3               ; if no, try to allocate
  3078.  
  3079.         or ecx,ecx                      ; is there a previous MCB?
  3080.         jz @@int310503rf6               ; if no, resize to next
  3081.  
  3082.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3083.         jne short @@int310503rf6        ; if not, resize to next
  3084.  
  3085.         mov ebp,[ecx-16]                ; EBP = size of previous block, try to
  3086.         add ebp,10h                     ;  resize within previous block
  3087.  
  3088.         sub ebp,ebx                     ; EBP = prev block size - needed size
  3089.         jbe short @@int310503rf7        ; if prev block too small, go on
  3090.  
  3091.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3092.         sub edi,ebp                     ;  resize will fit entirely
  3093.  
  3094.         lea eax,[ebp-10h]               ; EAX = new size of free block
  3095.         mov [ecx-16],eax                ; store mew free size in prev MCB
  3096.         mov [edi-16],edx                ; store new size in new MCB
  3097.         mov [ecx-12],edi                ; set next MCB in prev MCB to new MCB
  3098.         mov [edi-8],ecx                 ; set prev MCB in new MCB to prev MCB
  3099.         mov byte ptr [edi-4],1          ; set new MCB as used
  3100.  
  3101.         mov ecx,[esi-12]                ; copy next MCB field
  3102.         mov [edi-12],ecx
  3103.         or ecx,ecx                      ; is there a next MCB
  3104.         jz @@int310503rf0               ; if no, go to block readjust
  3105.  
  3106.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3107.  
  3108.         jmp @@int310503rf0              ; go to block readjust
  3109.  
  3110. @@int310503rf7:
  3111.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3112.  
  3113.         lea eax,[edx+ebp]               ; EAX = size of new block
  3114.         mov [edi-16],eax                ; store mew free size in new MCB
  3115.         mov byte ptr [edi-4],1          ; set new MCB as used
  3116.  
  3117.         mov ecx,[esi-12]                ; copy next MCB field
  3118.         mov [edi-12],ecx
  3119.         jecxz short @@int310503rf8      ; if no next MCB, go on
  3120.  
  3121.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3122.  
  3123. @@int310503rf8:
  3124.         add ebp,ebx                     ; EBP = size of block just acquired
  3125.         sub ebx,ebp                     ; EBX = new size still needed
  3126.         jz @@int310503rf0               ; if no more space needed, done
  3127.  
  3128.         mov esi,edi                     ; ESI -> new MCB
  3129.  
  3130. @@int310503rf6:
  3131.         mov edi,[esi-12]                ; EDI -> next MCB
  3132.  
  3133.         mov ecx,[edi-12]                ; copy next MCB field
  3134.         mov [esi-12],ecx
  3135.         jecxz short @@int310503rf9      ; if no next MCB, go on
  3136.  
  3137.         mov [ecx-8],esi                 ; set prev MCB in next MCB to this MCB
  3138.  
  3139. @@int310503rf9:
  3140.         mov eax,[edi-16]                ; EAX = size of next memory block
  3141.         add eax,10h
  3142.  
  3143.         sub edi,eax                     ; EDI -> start of next memory block
  3144.         sub eax,ebx                     ; EAX = amount of free space left
  3145.  
  3146.         mov ecx,[esi-16]                ; ECX = old size of this memory block
  3147.         mov [esi-16],edx                ; store new size in this MCB
  3148.         mov byte ptr [esi-4],1          ; set this MCB as used
  3149.  
  3150.         sub esi,ecx                     ; ESI -> start of this memory block
  3151.         sub esi,10h
  3152.  
  3153.         shr ecx,2                       ; copy this memory block down in mem
  3154.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3155.  
  3156.         add esi,10h                     ; adjust ESI to top MCB
  3157.         mov edi,esi                     ; EDI -> top MCB
  3158.  
  3159.         mov ebx,eax                     ; EBX = negative of space free at top
  3160.         neg ebx
  3161.         jz @@int310503rf0               ; in no space free, go to done
  3162.  
  3163.         jmp short @@int310503rf1        ; set new MCBs for moved block
  3164.  
  3165. @@int310503rf3:
  3166.         mov ebp,edi                     ; preserve old block MCB address
  3167.         sub edx,ebx                     ; EDX = size of old block
  3168.  
  3169.         mov bx,[esp+16]                 ; BX:CX = new block size from stack
  3170.         mov cx,[esp+24]
  3171.         mov ax,501h                     ; try to allocate new block
  3172.         int 31h
  3173.         jc int31failax                  ; if could not, fail with error AX
  3174.  
  3175.         shrd eax,esi,16                 ; EAX -> new block MCB
  3176.         mov ax,di
  3177.  
  3178.         shrd edi,ebx,16                 ; EDI -> start of new block
  3179.         mov di,cx
  3180.  
  3181.         lea esi,[ebp-10h]               ; ESI -> start of old block
  3182.         sub esi,edx
  3183.  
  3184.         mov ecx,edx                     ; copy memory from old block to new
  3185.         shr ecx,2
  3186.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3187.  
  3188.         mov edx,eax                     ; EDX -> new block MCB
  3189.  
  3190.         shld esi,ebp,16                 ; SI:DI = handle of old block
  3191.         mov di,bp
  3192.         mov ax,0502h                    ; free old block
  3193.         int 31h
  3194.  
  3195.         mov edi,edx                     ; EDI -> new block MCB for done
  3196.  
  3197.         jmp short @@int310503rf0        ; go to done
  3198.  
  3199. @@int310503rf1:
  3200.         lea edi,[esi+ebx]               ; EDI -> new MCB for new memory block
  3201.  
  3202.         lea eax,[ebx+10h]               ; EAX = size of freed block
  3203.         neg eax
  3204.         mov [esi-16],eax                ; store freed size in old MCB
  3205.         mov [edi-16],edx                ; store new size in new MCB
  3206.  
  3207.         mov ecx,[esi-12]                ; copy next MCB field
  3208.         mov [edi-12],ecx
  3209.         jecxz short @@int310503rf2      ; if no next MCB, go on
  3210.  
  3211.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3212.  
  3213. @@int310503rf2:
  3214.         mov [esi-12],edi                ; set next MCB in old MCB as new MCB
  3215.         mov [edi-8],esi                 ; set prev MCB in new MCB as old MCB
  3216.         mov byte ptr [edi-4],1          ; set new MCB as used
  3217.         mov byte ptr [esi-4],0          ; set old MCB as free
  3218.  
  3219.         mov ecx,[esi-8]                 ; ECX -> prev MCB of old MCB
  3220.         jecxz short @@int310503rf0      ; if no prev MCB, done
  3221.  
  3222.         cmp byte ptr [ecx-4],0          ; is previous MCB free?
  3223.         jne short @@int310503rf0        ; if no, dont link
  3224.  
  3225.         push edi                        ; preserve new MCB
  3226.         mov edi,ecx                     ; top MCB = prev MCB for link function
  3227.         call int310500rlinkmcb          ; link two memory blocks
  3228.         pop edi                         ; restore new MCB
  3229.  
  3230. @@int310503rf0:
  3231.         mov ecx,[edi-16]                ; ECX = base address of new block
  3232.         neg ecx
  3233.         lea ecx,[ecx+edi-10h]
  3234.         
  3235.         jmp int310501raddxnhandle       ; return address and handle
  3236.  
  3237. ;─────────────────────────────────────────────────────────────────────────────
  3238. int31050ar:                             ; raw get memory block size and base
  3239.         call int310500rfindmcb          ; find MCB for handle SI:DI
  3240.  
  3241.         mov edi,[esi-16]                ; EDI = size of memory block
  3242.         lea ecx,[esi-10h]               ; get base address of memory block
  3243.         sub ecx,edi
  3244.  
  3245.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  3246.         shld esi,edi,16                 ; SI:DI = EDI, size of memory block
  3247.  
  3248.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  3249.  
  3250. PMODE_TEXT      ends
  3251. end
  3252.  
  3253.